So I have a large file with the following types of lines:
public static string SyncButton = StringsProxy.GetStringByKey ("SyncButton") ?? "SYNC";
I need to replace this with the following version
public static string SyncButton {
get {
if (_SyncButton == null) {
_SyncButton = StringsProxy.GetStringByKey ("SyncButton") ?? "SYNC";
}
return _SyncButton;
}
set {
_SyncButton = value;
}
}
Can someone help construct a regular expression that could do a find and replace like this?
Replace this thing as regex:
public static string (.+?) = StringsProxy.GetStringByKey \("(.+?)"\) \?\? "(.+?)";
with this one:
public static string \1 {
get {
if (_\1 == null) {
_\1 = StringsProxy.GetStringByKey ("\1") ?? "\3";
}
return _\1;
}
set {
_\1 = value;
}
}
Example:
!
try this
Find What:
public static string ([^= ]*) (= StringsProxy\.GetStringByKey \("SyncButton"\) \?\? "SYNC";)
Replace With:
public static string \1 {
get {
if (_\1 == null) {
_\1 = \2
}
return _\1;
}
set {
_\1 = value;
}
}
Related
I have this method:
namespace MyProject.String.Utils
{
public static class String
{
public static void formatDecimalSeparator(this string paramString)
{
try
{
if (System.Globalization.NumberFormatInfo.CurrentInfo.NumberDecimalSeparator == ",")
{
paramString = paramString.Replace(".", ",");
}
else
{
paramString = paramString.Replace(",", ".");
}
}
catch
{
throw;
}
}
}
}
But when I do this:
string myString = "1.23";
myString.formatDecimalSeparator();
The result is not "1,23". The variable is not updated. So I have to change the method to return a string and assign the return value to the same variable.
Why is the variable not updated at the call site? The extension method gets the value of the variable paramString, I can change it in the method, but in the main code the variable is not changed?
You need to set return type as string.
public static string formatDecimalSeparator(this string paramString)
{
try
{
if (System.Globalization.NumberFormatInfo.CurrentInfo.NumberDecimalSeparator == ",")
return paramString.Replace(".", ",");
else
return paramString.Replace(",", ".");
}
catch
{
throw;
}
}
and then you have to assign the returned variable:
myString = myString.formatDecimalSeparator();
Strings are immutable. Whenever any change is done in a string, a new instance with changes is returned. Read String is immutable. What exactly is the meaning?.
Tried and Tested
Strings are immutable, so you can't change the string. A reference to the string is passed to the method, but when you try to change the string you are actually changing the reference to point to a new string. The code outside the method still has the reference to the original string.
String methods return a new string, so that is what you would do in your extension method:
namespace MyProject.String.Utils
{
public static class String
{
public static string formatDecimalSeparator(this string paramString)
{
if (System.Globalization.NumberFormatInfo.CurrentInfo.NumberDecimalSeparator == ",")
{
return paramString.Replace(".", ",");
}
else
{
return paramString.Replace(",", ".");
}
}
}
}
Usage:
string myString = "1.23";
myString = myString.formatDecimalSeparator();
If you want to not return anything, you should pass the string as reference !
public static void formatDecimalSeparator(ref string paramString)
{
try
{
if (System.Globalization.NumberFormatInfo.CurrentInfo.NumberDecimalSeparator == ",")
{
paramString = paramString.Replace(".", ",");
}
else
{
paramString = paramString.Replace(",", ".");
}
}
catch
{
throw;
}
}
I've a text file and I've to read the text file and then I've to convert the file data in the form of a table.
The file is in this form
{KeyValuePair}
{
Key1 = Value1 {next}
Key2 = Value2 {next}
Key3 = Value3 {next}
Key4 = {KeyValuePair} {
KeyA = ValueA {next}
KeyB = ValueB {next}
KeyC = ValueC {next}
}
}
and I need a output like this
My logic code is Here
StreamReader reader = new StreamReader("C:\\Users\\Kaushik Kishore\\Documents\\TextToRead.txt");
string data = reader.ReadToEnd();
//string[] stringSeparater = new string[] { "{KeyValuePair}" };
//string[] getData = data.Split(stringSeparater, StringSplitOptions.None);
//string[] separater = new string[] { "{next}" };
//string[] nextSplit = data.Split(separater, StringSplitOptions.None);
string pattern = #"(=)|(next)|(KeyValuePair)|({)|(})";
string[] output = Regex.Split(data, pattern);
foreach (string one in output)
{
Response.Write(one);
}
so thing I'm facing the problem is how to write the actual logic to extract the desired string.
Next specifies that We have to change the row in the table. each time the next keyword will occur I've to post the data in new Row.
Thanks in Advance
EDIT
I've done some effort and write some code
This is printing the data fine now I want to know how to pass the data from controller to view. when the data is coming in loop parts.
public ActionResult Index()
{
StreamReader reader = new StreamReader("C:\\Users\\Kaushik Kishore\\Documents\\Text2.txt");
string data = reader.ReadToEnd();
// replacing all tabs white space new line and everything
string trimmedData = Regex.Replace(data, #"\s", "");
string pattern = #"({next})|({KeyValuePair}{)|(}{next})";
string[] output = Regex.Split(trimmedData, pattern);
int length = output.Length;
int count = 0;
foreach (string one in output)
{
count++;
if (one == "{KeyValuePair}{")
{
Response.Write("Table Create</br>");
}
else if (count == length)
{
string[] last = one.Split('=');
foreach (string lastVal in last)
{
Response.Write(lastVal.Substring(0,lastVal.Length-1));
Response.Write('|');
}
}
else
{
string[] keyVal = one.Split('=');
foreach (string val in keyVal)
{
if (val == "{next}")
{
Response.Write("</br>");
}
else if (val == "}{next}")
{
Response.Write("Subtable End</br>");
}
else if (val == "}")
{
Response.Write("");
}
else
{
Response.Write(val);
Response.Write("|");
}
}
}
}
reader.Close();
return View();
}
This will be your controller part
public ActionResult Index()
{
ViewBag.DisplayTable = GetKeyValueDisplayContent(#"YourFilePath.Txt");
return View();
}
private string GetKeyValueDisplayContent(string fileToRead)
{
// 01 Get Data
string DataToProcess = GetDataToProcess(fileToRead);
// 02 Cleaning Data (replacing all tabs white space new line and everything)
DataToProcess = CleanDataToProcess(DataToProcess);
// 03 Retrieve Array from Data format
string[] output = GetDataInArray(DataToProcess);
// 04 Displaying Result
string DrawTable = GetDisplayHTML(output);
return DrawTable;
}
private string GetDataToProcess(string fileToRead)
{
StreamReader reader = new StreamReader(fileToRead);
string data = reader.ReadToEnd();
reader.Close();
return data;
}
private string CleanDataToProcess(string dataToProcess)
{
return Regex.Replace(dataToProcess, #"\s", "");
}
private string[] GetDataInArray(string dataToProcess)
{
string pattern = #"({next})|({KeyValuePair}{)|(}{next})";
string[] output = Regex.Split(dataToProcess, pattern);
return output;
}
private string GetDisplayHTML(string[] output)
{
int length = output.Length;
int count = 0;
StringBuilder OutputToPrint = new StringBuilder();
foreach (string one in output)
{
if (one == "{KeyValuePair}{")
{
count++;
if (count >= 2)
{
OutputToPrint.Append("<td><table border = \"1\">");
}
else
{
OutputToPrint.Append("<table border = \"1\">");
}
}
else if (one.Contains("=") == true)
{
string[] keyVal = Regex.Split(one, #"=");
OutputToPrint.Append("<tr>");
foreach (string val in keyVal)
{
if (val != "")
{
OutputToPrint.Append("<td>");
OutputToPrint.Append(WebUtility.HtmlEncode(val));
OutputToPrint.Append("</td>");
}
}
}
else if (one.Equals("{next}"))
{
OutputToPrint.Append("</tr>");
}
else if (one.Contains("}{next}") == true)
{
OutputToPrint.Append("</table></td>");
}
else if (one == "}")
{
OutputToPrint.Append("</table>");
}
else { }
}
return OutputToPrint.ToString();
}
This will be the View
<div>
#Html.Raw(ViewBag.DisplayTable)
</div>
Hope You'll find this well
if you use this little pattern, and if you use it recursively on the value capturing group, I think you can obtain what you want:
string pattern = #"(?>\s*(?<key>[^\s=]+)\s*=\s*|^\s*)(?>{KeyValuePair}\s*{\s*(?<value>(?>(?<c>{)|(?<-c>})|[^{}]+)+(?(c)(?!)))\s*}|(?<value>[^\s{]+)\s*(?<next>{next})\s*)";
pattern details:
(?> # possible begin of the match
\s*(?<key>[^\s=]+)\s*=\s* # a keyname
| # OR
^\s* # the start of the string
)
(?>
# case KeyValuePair #
{KeyValuePair} \s* { \s*
(?<value>
(?>(?<c>{)|(?<-c>})|[^{}]+)+ (?(c)(?!)) # content inside balanced curly brackets*
)
\s* }
| OR
# case next #
(?<value>
[^\s{]+ # all that is not a white character or an opening curly bracket
)
\s*
(?<next> {next} )\s* # the goal of this capture is to know in which case you are
)
(*)You can find more explanations about balancing groups here: What are regular expression Balancing Groups?
The idea is to write a recursive method that will call itself when the pattern matches the "keyValuePair" case. In the "next" case, the method records only the key/value in an array (or this kind of structure). The method must return this kind of array.
I created a parser-based solution that outputs a dictionary containing the key value pairs. It can nest {KeyValuePair}s as deep as you want.
Use like this:
string data = File.ReadAllText("data.txt");
var p = new Parser(text);
Dictionary<string, Value> dictionary = p.Parse();
A value can be either a string or a dictionary:
public abstract class Value { }
public class StringValue : Value
{
public string Value { get; private set; }
public StringValue(string value)
{
this.Value = value;
}
}
public class DictionaryValue : Value
{
public Dictionary<string, Value> Values { get; private set; }
public DictionaryValue()
{
this.Values = new Dictionary<string, Value>();
}
}
This allows for error reporting:
public class ParseError : Exception
{
public ParseError(string message)
: base(message) { }
}
The parser consists of two things.
The tokenizer, which transforms the input text to a stream of tokens:
KeyValuePair, OpenBracket, KeyOrValue(Key1) , Assign,
KeyOrValue(Value1) , Next, KeyOrValue(Key2) , Assign,
KeyOrValue(Value2) , Next, KeyOrValue(Key3) , Assign,
KeyOrValue(Value3) , Next, KeyOrValue(Key4) , Assign, KeyValuePair,
OpenBracket, KeyOrValue(KeyA) , Assign, KeyOrValue(ValueA) , Next,
KeyOrValue(KeyB) , Assign, KeyOrValue(ValueB) , Next, KeyOrValue(KeyC)
, Assign, KeyOrValue(ValueC) , Next, CloseBracket, CloseBracket, End
And then the parser, which transforms the token stream into a dictionary.
Here is the complete code:
public class Parser
{
private Tokenizer tk;
public Parser(string text)
{
this.tk = new Tokenizer(text);
}
public Dictionary<string, Value> Parse()
{
Stack<Dictionary<string, Value>> dictionaries = new Stack<Dictionary<string, Value>>();
Token t;
while ((t = tk.ReadToken()) != Token.End)
{
switch (t)
{
case Token.KeyValuePair:
t = tk.ReadToken();
if (t != Token.OpenBracket)
throw new ParseError("{KeyValuePair} should be followed by a '{'");
dictionaries.Push(new Dictionary<string, Value>());
break;
case Token.CloseBracket:
if (dictionaries.Count > 1)
dictionaries.Pop();
break;
case Token.KeyOrValue:
string key = tk.TokenValue;
t = tk.ReadToken();
if (t != Token.Assign)
throw new ParseError("Key should be followed by a '='");
t = tk.ReadToken();
if (t == Token.KeyValuePair)
{
var value = new DictionaryValue();
dictionaries.Peek().Add(key, value);
dictionaries.Push(value.Values);
}
else if (t != Token.KeyOrValue)
throw new ParseError("Value expected after " + key + " =");
else
{
string value = tk.TokenValue;
dictionaries.Peek().Add(key, new StringValue(value));
t = tk.ReadToken();
if (t != Token.Next)
throw new ParseError("{next} expected after Key value pair (" + key + " = " + value + ")");
}
break;
case Token.Error:
break;
default:
break;
}
}
return dictionaries.Peek();
}
private class Tokenizer
{
private string _data;
private int currentIndex = 0;
private string tokenValue;
public string TokenValue
{
get { return tokenValue; }
}
public Tokenizer(string data)
{
this._data = data;
}
public Token ReadToken()
{
tokenValue = string.Empty;
if (currentIndex >= _data.Length) return Token.End;
char c = _data[currentIndex];
if (char.IsWhiteSpace(c))
{
currentIndex++;
return ReadToken();
}
else if (c == '{')
{
if (TryReadBracketedToken("KeyValuePair"))
{
currentIndex++;
return Token.KeyValuePair;
}
else if (TryReadBracketedToken("next"))
{
currentIndex++;
return Token.Next;
}
else
{
currentIndex++;
return Token.OpenBracket;
}
}
else if (c == '}')
{
currentIndex++;
return Token.CloseBracket;
}
else if (c == '=')
{
currentIndex++;
return Token.Assign;
}
else
{
StringBuilder valueBuilder = new StringBuilder();
while (currentIndex < _data.Length && !char.IsWhiteSpace(c))
{
valueBuilder.Append(c);
currentIndex++;
c = _data[currentIndex];
}
tokenValue = valueBuilder.ToString();
return Token.KeyOrValue;
}
}
private bool TryReadBracketedToken(string token)
{
bool result = _data.Length > currentIndex + token.Length + 2
&& _data.Substring(currentIndex + 1, token.Length + 1) == token + "}";
if (result)
{
currentIndex++;
currentIndex += token.Length;
}
return result;
}
}
private enum Token
{
KeyValuePair,
Next,
OpenBracket,
CloseBracket,
Assign,
KeyOrValue,
End,
Error
}
}
public abstract class Value { }
public class StringValue : Value
{
public string Value { get; private set; }
public StringValue(string value)
{
this.Value = value;
}
}
public class DictionaryValue : Value
{
public Dictionary<string, Value> Values { get; private set; }
public DictionaryValue()
{
this.Values = new Dictionary<string, Value>();
}
}
public class ParseError : Exception
{
public ParseError(string message)
: base(message) { }
}
Return the value only when it is available. if I use a condition to check the null condition it is throwing a exception. "saying not all code paths return a value"
internal PinMessage()
{
obj.PinsAvailable.ObserveOn(SynchronizationContext.Current).Subscribe(HandlePinsAvailable);
}
private void HandlePinsAvailable(byte[] pinBytes)
{
pinmesssage = Encoding.ASCII.GetString(pinBytes);
}
internal string GetPinMessage(string AccoutNumber)
{
string pinstring = string.Empty;
obj.SendPinRequest(AccoutNumber);
pinstring = pinmesssage;
return pinstring;
}
private string _pinMessage;
public string pinmesssage
{
get//Not all Code paths return a value
{
if (_pinMessage != null)
return _pinMessage;
}
set { _pinMessage = value; }
}
You are getting this compile error because you don't return anything in the case where _pinMesSafe is null. You need to return something from your Access or in the case when that is true, or throw an exception.
private string _pinMessafe;
public string pinmesssage
{
get {
if (_pinMessafe != null)
return _pinMessafe;
}
set { _pinMessafe = value; }
}
You have to return something when it's being called, you can't just put a method call on hold.
What you could do is force a check yourself:
private string _pinMessafe;
public string pinmesssage
{
get {
return _pinMessafe ?? GetMessage()
}
set { _pinMessafe = value; }
}
In this scenario, GetMessage() would have to take care of returning the message. It's hard to give a more detailed answer with the information you've provided.
You should edit your code to make it more readable (this includes the english spelling errors) and add info if needed.
This is not the "best" practice, but will work and let your consumer wait until the producer has written the variable.
private string _pinMessafe;
object locker = new object();
public string pinmesssage
{
get
{
string x = null;
while(x == null) {
lock(locker) { x = _pinMessafe ; }
Thread.Sleep(1);
}
return x;
}
set { lock(locker) { _pinMessafe = value; } }
}
I've got something like this in my property/accessor method of a constructor for my program.
using System;
namespace BusinessTrips
{
public class Expense
{
private string paymentMethod;
public Expense()
{
}
public Expense(string pmtMthd)
{
paymentMethod = pmtMthd;
}
//This is where things get problematic
public string PaymentMethod
{
get
{
return paymentMethod;
}
set
{
if (string.IsNullOrWhiteSpace(" "))
paymentMethod = "~~unspecified~~";
else paymentMethod = value;
}
}
}
}
When a new attribute is entered, for PaymentMethod, which is null or a space, this clearly does not work. Any ideas?
do you perhaps just need to replace string.IsNullOrWhiteSpace(" ") with string.IsNullOrWhiteSpace(value) ?
From your posted code, you need to call:
this.PaymentMethod = pmtMthd;
instead of
paymentMethod = pmtMthd;
The capital p will use your property instead of the string directly. This is why it's a good idea to use this. when accessing class variables. In this case, it's the capital not the this. that makes the difference, but I'd get into the habit of using this.
Jean-Barnard Pellerin's answer is correct.
But here is the full code, which I tested in LinqPad to show that it works.
public class Foo {
private string _paymentMethod = "~~unspecified~~";
public string PaymentMethod
{
get
{
return _paymentMethod;
}
set
{
if (string.IsNullOrWhiteSpace(value))
_paymentMethod = "~~unspecified~~";
else _paymentMethod = value;
}
}
}
With a main of:
void Main()
{
var f = new Foo();
f.PaymentMethod = "";
Console.WriteLine(f.PaymentMethod);
f.PaymentMethod = " ";
Console.WriteLine(f.PaymentMethod);
f.PaymentMethod = "FooBar";
Console.WriteLine(f.PaymentMethod);
}
Output from console:
~~unspecified~~
~~unspecified~~
FooBar
I want to preserve a property between postbacks in an ASP.Net application. Currently doing this:
public int MyIndex
{
get
{
return (int)Session[ToString() + "MyIndex"];
}
}
but would prefer something like:
public int MyIndex
{
get
{
return (int)Session[ToString() + #code_that_returns_property_name#];
}
}
Setter omitted, but it just pushes value into Session using the same string.
Is there some way to use reflection, or a different better solution?
public static int Dummy {
get {
var propertyName = MethodBase.GetCurrentMethod().Name.Substring(4);
Console.WriteLine(propertyName);
return 0;
}
}
Using CallerMemberName is a lot faster and it can be copied and pasted easily for additional properties.
private static object GetSessionValue([CallerMemberName]string propertyName = "")
{
return Session[propertyName];
}
private static void SetSessionValue(object value, [CallerMemberName]string propertyName = "")
{
Session[propertyName] = value;
}
public int MyIndex
{
get { return (int)GetSessionValue(); }
set { SetSessionValue(value); }
}
No, there isn't a simple way to do what you want to do. I think you are much better off with the code you have already written.
Edit: This answer has received quite a few downvotes and I do understand why. While it is possible to do what the OP wants to do perhaps we should all stop and think whether or not it is advisable to do so. To paraphrase the immortal words of Dr. Ian Malcom, just because you can do something doesn't mean you should.
You can use MethodInfo.GetCurrentMethod().Name to return the name of the current method:
public int MyIndex
{
get
{
return (int)Session[ToString() + MethodInfo.GetCurrentMethod().Name];
}
}
Since properties are implemented as methods under the hood, that will return a name like "get_MyIndex". If you don't want the "get_" part, you can substring out a few characters:
public int MyIndex
{
get
{
return (int)Session[ToString() + MethodInfo.GetCurrentMethod().Name.Substring(4)];
}
}
You can use an expression tree to get the member name. It's a bit of a hock but it works. Here is the code.
private string GetPropertyName<TValue>(Expression<Func<BindingSourceType, TValue>> propertySelector)
{
var memberExpression = propertySelector.Body as MemberExpression;
if (memberExpression != null)
{
return memberExpression.Member.Name;
}
else
{
return string.empty;
}
}
With that code you can do the following
return (int)Session[ToString() + GetPropertyName(MyIndex)];
Code ruthlessly stolen from Romain's answer on the following thread
Get class property name
You should rather use the ViewState property of your control:
public int MyIndex {
get {
object index = ViewState["MyIndex"];
return (null == index) ? -1 : (int)index;
}
set {
ViewState["MyIndex"] = value;
}
}
While Brian Rice answered the optimized version, I needed it for another usage. Without optimization for a session/dictionary code would look like this:
private static string GetPropertyName([CallerMemberName] string propertyName = "")
{
return propertyName;
}
And usage:
public int MyIndex
{
get
{
return (int)Session[ToString() + GetPropertyName()];
}
//or one liner
get=>(int)Session[ToString() + GetPropertyName()];
}