How to replace variable in user input with math operation? - c#

I need replace variable in string from user. For example:
User input: Ssad asdsdqwdq jdiqwj diqw jd qwld j {price-40%} asd asd asd
I know how replace only {price} but I don't know how to replace other cases.
I need support these cases:
{price}
{price-xx%}
{price+xx%}
{price-xx}
{price+xx}
{price/xx}
{price*xx}
And user can use variable {price} many times.
After user submit text, my app replace variable {price} or calc {price-xx%} and create a new string.

If I understood your problem correctly then I think you can evaluate the whole expression without Replacing variables (might you have to change placements of variables)
First, add 'System.Data' name space in your project
then:
double price = 110;
double xx = 15;
double result = 0;
result = Convert.ToDouble(new DataTable().Compute($"({price-(price*xx)/100})", null));
Console.WriteLine("{price - xx%} = " + result);
result = Convert.ToDouble(new DataTable().Compute($"({price + (price * xx) / 100})", null));
Console.WriteLine("{price + xx%} = " + result);
result = Convert.ToDouble(new DataTable().Compute($"({price}-{xx})", null));
Console.WriteLine("{price - xx} = " + result);
result = Convert.ToDouble(new DataTable().Compute($"({price}+{xx})", null));
Console.WriteLine("{price + xx} = " + result);
result = Convert.ToDouble(new DataTable().Compute($"({price}/{xx})", null));
Console.WriteLine("{price / xx} = " + result);
result = Convert.ToDouble(new DataTable().Compute($"({price}*{xx})", null));
Console.WriteLine("{price * xx} = " + result);

https://github.com/davideicardi/DynamicExpresso/
static void Main(string[] args)
{
int price = 100;
Regex regex = new Regex(#"(?<=\{).*?(?=\})");
string userInput = "Hi. I want to buy your computer. I can't offer {price} USD, but I can offer {price-(price/100)*10} USD";
string text = userInput;
foreach (var item in regex.Matches(text))
{
string expression = item.ToString().Replace("price", price.ToString());
var interpreter = new Interpreter();
var result = interpreter.Eval(expression);
text = regex.Replace(text, result.ToString(),1);
text = ReplaceFirst(text, "{", string.Empty);
text = ReplaceFirst(text, "}", string.Empty);
}
Console.WriteLine("Result: " + text);
}
public static string ReplaceFirst(string text, string search, string replace)
{
int pos = text.IndexOf(search);
if (pos < 0)
{
return text;
}
return text.Substring(0, pos) + replace + text.Substring(pos + search.Length);
}

Related

C# multiple increments

I have, code who do for me "x + y = z"
if (command.Contains("+")) // string polecenie = "";'
{
polecenie = "{" + command + ")";
polecenie = polecenie.Replace("+", "}(");
double a = Convert.ToDouble(Between(polecenie, "{", "}"));
double b = Convert.ToDouble(Between(polecenie, "(", ")"));
double wyn = a + b;
richTextBox1.Text += a + " + " + b + " is " + wyn + "\r\n";
}
And when 'command' is "4+5","3 + 4" or something like this code works, but when i try to do "4 + 3 + 23" it don't work. Final string with starting 'command' "4+5+6", polecenie is: "{4}(5}(6)"... The Between Method:
public string Between(string content, string First, string Last)
{
string end = "";
int Plc1 = content.IndexOf(First) + First.Length;
int Plc2 = content.IndexOf(Last);
end = content.Substring(Plc1, Plc2 - Plc1);
return end;
}
How can I do that? (I want it to work with all possible additions ("4+4","34+5+54","43+4+65+54"...)
You could use the DataTable object to not re-invent the wheel.
richTextBox1.Text = string.Format("{0} is {1}\r\n", command,
(new System.Data.DataTable()).Compute(command, string.Empty));
This would support +, -, *, / and % (mod) operators. For more: https://msdn.microsoft.com/en-us/library/system.data.datacolumn.expression.aspx

String split// manipulation

string keywords = "heard";
string strText = "Have you not heard!! what I said?"
string[] words = strText.Split(' ');
string result = "";
for (int i = 0; i < words.Length; i++)
{
if (words[i].Contains(keywords))
result += "<span>" + words[i] + "</span>" + " ";
else
result += words[i] + " ";
}
I get following output:
Have you not <span>heard!!</span> what I said?
Desired output:
Have you not <span>heard</span>!! what I said?
Can someone guide how can I get the desired output. The strText can only be split with a space.
Use String.Replace
var result = strText.Replace(keywords, "<span>" + keywords + "</span>");
If you have many keywords to replace, then just do replacement in a loop:
string[] keywords = { "heard", "said" };
string result = "Have you not heard!! what I said?";
foreach(var keyword in keywords)
result = result.Replace(keyword, "<span>" + keyword + "</span>");
Alternative solution is regular expression replacement:
string keywords = "heard|said";
string result = "Have you not heard!! what I said?";
result = Regex.Replace(result, keywords, m => "<span>" + m.Value + "</span>");
Why are you even looping through all words? This will give you the same:
string strText = "Have you not heard!! what I said?";
string newText = strText.Replace("heard", "<span>heard</span>");

From DataGridView to multiline commaSeparated string

I have a DataGridView with four Columns and need to crate a multiline string from its content, separated by comma.
This code works, but probably - there is a more elegant way:
string multiLine = "";
string singleLine;
foreach (DataGridViewRow r in dgvSm.Rows)
{
if (!r.IsNewRow)
{
singleLine = r.Cells[0].Value.ToString() + ","
+ r.Cells[1].Value.ToString() + ","
+ r.Cells[2].Value.ToString() + ","
+ r.Cells[3].Value.ToString() + Environment.NewLine;
multiLine = multiLine + singleLine;
}
}
I don't know about elegant, but:
use StringBuilder for string manipulation, type string is immutable!
if you need to do something in between, separate first or last cycle running (e.g. comma separation)
So, basically something like this:
StringBuilder multiLine = new StringBuilder();
foreach (DataGridViewRow r in dgvSm.Rows)
{
if (!r.IsNewRow)
{
if (r.Cells.Count > 0)
{
multiLine.Append(r.Cells[0].Value.ToString()); //first separated
for (int i = 1; i < r.Cells.Count; ++i)
{
singleLine.Append(','); //between values
singleLine.Append(r.Cells[i].Value.ToString());
}
multiLine.AppendLine();
}
}
}
To illustrate speed difference between StringBuilder concatenation (just dynamic array of characters) and string (new object and copy everything each time you use operator + concatenation), have a look at mini-program:
public static void Main()
{
var sw = new Stopwatch();
sw.Start();
StringBuilder s = new StringBuilder();
//string s = "";
int i;
for (i = 0; sw.ElapsedMilliseconds < 1000; ++i)
//s += i.ToString();
s.Append(i.ToString());
sw.Stop();
Console.WriteLine("using version with type " + s.GetType().Name + " I did " +
i + " times of string concatenation.");
}
For my computer it is:
using version with type String I did 17682 times of string concatenation.
using version with type StringBuilder I did 366367 times of string concatenation.
Try this :
string multiLine = "";
string singleLine;
foreach (DataGridViewRow r in dgvSm.Rows)
{
if (!r.IsNewRow)
{
singleLine = r.Cells[0].Value.ToString() + ","
+ r.Cells[1].Value.ToString() + ","
+ r.Cells[2].Value.ToString() + ","
+ r.Cells[3].Value.ToString() + "\r\n";
multiLine = multiLine + singleLine;
}
}

Select string from certain character until certain character in c#

Okay so my code looks kinda like this
// Returns the note of a favorite pown if it exists
string GetFavoriteNote(int id)
{
string notelist = Properties.Settings.Default.FavoriteNotesList;
// If there's a note, return it
if (notelist.Contains("'" + id + ":"))
{
// What to do here?
}
// If there's no note, return an empty string
else
{
return String.Empty;
}
}
Now it's basically a system where for each id the user can set a note, and it will be saved in this format: 'id:note','id:note',
Now what I want to do is select that note somehow and return it, so I'd have to like select from "'" + id + ":" until the '
If anyone knows how to do this, please help me out.
Thanks
Using a Regex seems like the cleanest approach to me:
string regexFormat = "'{0}:(.*?)'";
Match match = Regex.Match(notelist, string.Format(regexFormat, id));
return match.Success ? match.Groups[1].Value : string.Empty;
Alternatively however, you could use string splitting:
var notes = notelist.Split(',');
var idString = "'" + id + ":";
var note = notes.FirstOrDefault(n => n.StartsWith(idString));
if (note == null) return string.Empty;
return note.Substring(idString.Length, note.Length - (idString.Length + 1));
try
int StartIndex = notelist.IndexOf("'" + id.ToString() + ":");
string result = string.Empty;
if ( StartIndex >= 0 )
{
string tempstr = notelist.SubString ( StartIndex + ("'" + id.ToString() + ":").Length );
result = tempstr.SubString ( 0, tempstr.IndexOf ( "'" ) );
}
return result;
As far I understood your code, following code will kinda give you a solution
string IdWithNote = string.Empty;
string noteList = Properties.Settings.Default.FavoriteNotesList;//your string type note list
List<string> listNote = new List<string>();//newly created string type collection
listNote=noteList.Split(',').ToList<string>();
int index=listNote.IndexOf("'" + id + ":");
if (index > -1)
IdWithNote = listNote[index];
return IdWithNote;
Old fashoned & clear (no regex) Also assumes you only want the text of the note, not the entire note structure.
string key = "'" + id + ":";
int noteStart = noteList.IndexOf(key);
if (noteStart >= 0)
{
int textStart = noteStart + key.Length;
int textEnd = noteList.IndexOf("'", textStart);
return noteList.Substring(textStart, textEnd - textStart);
}
return "";
var myId=2;
var t="'1:note1','2:note2'";
var query = t.Split(',').Select(c => c.Replace("'", "").Split(':')).
Where(c => c[0] == myId.ToString()).
Select(p=>p[1]).First();
Here is a bit of code - the line you really wanted is: retVal = noteList.Substring(startIndex, endIndex - startIndex);
int id = 8;
string noteList = "'8:the note i want','81:the note i do not want'";
string toFind = "'" + id.ToString() + ":";
int startIndex = noteList.IndexOf(toFind) + toFind.Length;
int endIndex = noteList.IndexOf("'", startIndex);
if (noteList.Contains(toFind))
{
retVal = noteList.Substring(startIndex, endIndex - startIndex);
}
else
{
retVal = "nothing found";
}
notelist.Substring(notelist.IndexOf("'" + id + ":"), (notelist.IndexOf("'") - notelist.IndexOf("'" + id + ":")));
this should do the trick, you can select the text by a substring into a new string. substring(startindex, lenght);

Variable String.Format length

I have the following code:
var str = "ABC";
var n = 7;
var output = String.Format("{0,n}", str);
This should output the string
" ABC"
How should I change the line above?
Format strings are just strings too - you can define the format separately:
int n = 3;
string format = string.Format("{{0,{0}}}", n);
//or more readable: string format = "{0," + n + "}";
var output = string.Format(format, str);
Edit:
After your update it looks like what you want can also be achieved by PadLeft():
var str = "ABC";
string output = str.PadLeft(7);
Just write:
var lineLength = String.Format("{0," + n + "}", str);
var s="Hello my friend";
string leftSpace = s.PadLeft(20,' '); //pad left with special character
string rightSpace = s.PadRight(20,' '); //pad right with special character

Categories