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;
}
}
Related
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);
}
I am writing to a csv file and one of the values to be written to a row has a string literal in it as part of the value and I need it to remain in the value:
Example of the value:
"<span><span style=\"font-family: arial,sans-serif;\"><\span><\span>"
What is happening is the instead of keeping this under one column the comma forces it into the next column as the writer thinks this is what it is supposed to do.
My method:
var value = "";
var fileReadIn = new StreamReader(fileName);
var headerFields = CsvRowToStringArray(fileReadIn.ReadLine());
fileReadIn.Close();
for (int i = 0; i < headerFields.Length - 1; i++)
{
if (dict.ContainsKey(headerFields[i]))
{
if (dict[headerFields[i]].Contains("\n"))
{
Console.WriteLine("hell");
Console.ReadKey();
value += "\"" + dict[headerFields[i]].Replace("\n", #"\n").Replace(#"\", #"""\""" ).Replace(#"/", #"""/""")
+"\"" + ",";
}
else
{
value += #"""" + dict[headerFields[i]] + #"""" + ",";
}
}
else
{
value += #"""" + "Null" + #"""" + ",";
}
}
dict.Clear();
return value;
As long as the string literal is not present it wraps the rows quotes and that fixes any comma issue, however I've tried using both methods below however am not having any luck
I want to read string variable that contains this:
==title1==
text1...
==title2==
text2...
.
.
.
etc
I want to retrieve title1, title2 and etc sub strings, then create separate files like this:
title1.txt contains text1
title2.txt contains text2
how can I do this?
string[] split = yourString.Split(new string[] { "==" }, StringSplitOptions.None);
That will give you an array with these entrys: title1, text1, title2, text2 etc.
Now when you iterate through the array you will have the title every second loop. So increment by 2 and you will have the title at i and the corresponding text at i+1.
for (int i = 0; i < split.Length; i+=2){
File.WriteAllText("yourPath/" + split[i] + ".txt", split[i+1]);
}
I solve it by change code to this:
_edit = edit.InnerText.Replace("\n", Environment.NewLine);
// _edit = edit.InnerText.Replace("<lt;ref&", "<ref>");
// _edit = edit.InnerText.Replace("</ref>", "</ref>");
string[] split = _edit.Split(new[] { "==" }, StringSplitOptions.None);
System.IO.Directory.CreateDirectory(path + title);
using (StreamWriter sw = new StreamWriter(path + title + "\\" + "مقدمه.txt"))
{
sw.WriteLine(split[0]);
}
for (int i = 1; i < split.Length; i += 2)
{
//split[i].Replace("=", " ");
//File.WriteAllText(path + split[i] + ".txt", split[i + 1]);
using (StreamWriter sw = new StreamWriter(path + title + "\\" + split[i] + ".txt"))
{
// Add some text to the file.
sw.WriteLine(split[i + 1]);
}
}
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>");
I wish to implement a fairly simple CSV checker in my C#/ASP.NET application - my project automatically generates CSV's from GridView's for users, but I want to be able to quickly run through each line and see if they have the same amount of commas, and throw an exception if any differences occur. So far I have this, which does work but there are some issues I'll describe soon:
int? CommaCount = null;
StringBuilder sb = new StringBuilder();
StringWriter sw = new StringWriter(sb);
String Str = null;
//This loops through all the headerrow cells and writes them to the stringbuilder
for (int k = 0; k <= (grd.Columns.Count - 1); k++)
{
sw.Write(grd.HeaderRow.Cells[k].Text + ",");
}
sw.WriteLine(",");
//This loops through all the main rows and writes them to the stringbuilder
for (int i = 0; i <= grd.Rows.Count - 1; i++)
{
StringBuilder RowString = new StringBuilder();
for (int j = 0; j <= grd.Columns.Count - 1; j++)
{
//We'll need to strip meaningless junk such as <br /> and
Str = grd.Rows[i].Cells[j].Text.ToString().Replace("<br />", "");
if (Str == " ")
{
Str = "";
}
Str = "\"" + Str + "\"" + ",";
RowString.Append(Str);
sw.Write(Str);
}
sw.WriteLine();
//The below code block ensures that each row contains the same number of commas, which is crucial
int RowCommaCount = CheckChar(RowString.ToString(), ',');
if (CommaCount == null)
{
CommaCount = RowCommaCount;
}
else
{
if (CommaCount!= RowCommaCount)
{
throw new Exception("CSV generated is corrupt - line " + i + " has " + RowCommaCount + " commas when it should have " + CommaCount);
}
}
}
sw.Close();
And my CheckChar method:
protected static int CheckChar(string Input, char CharToCheck)
{
int Counter = 0;
foreach (char StringChar in Input)
{
if (StringChar == CharToCheck)
{
Counter++;
}
}
return Counter;
}
Now my problem is, if a cell in the grid contains a comma, my check char method will still count these as delimiters so will return an error. As you can see in the code, I wrap all the values in " characters to 'escape' them. How simple would it be to ignore commas in values in my method? I assume I'll need to rewrite the method quite a lot.
var rx = new Regex("^ ( ( \"[^\"]*\" ) | ( (?!$)[^\",] )+ | (?<1>,) )* $", RegexOptions.ExplicitCapture | RegexOptions.IgnorePatternWhitespace | RegexOptions.Multiline);
var matches = rx.Matches("Hello,World,How,Are\nYou,Today,This,Is,\"A beautiful, world\",Hi!");
for (int i = 1; i < matches.Count; i++) {
if (matches[i].Groups[1].Captures.Count != matches[i - 1].Groups[1].Captures.Count) {
throw new Exception();
}
}
You could just use a regular expression that matches one item and count the number of matches in your line. An example of such a regex is the following:
var itemsRegex =
new Regex(#"(?<=(^|[\" + separator + #"]))((?<item>[^""\" + separator +
#"\n]*)|(?<item>""([^""]|"""")*""))(?=($|[\" + separator + #"]))");
Just do something like the following (assuming you don't want to have " inside your fields (otherwise these need some extra handling)):
protected static int CheckChar(string Input, char CharToCheck, char fieldDelimiter)
{
int Counter = 0;
bool inValue = false;
foreach (char StringChar in Input)
{
if (StringChar == fieldDelimiter)
inValue = !inValue;
else if (!inValue && StringChar == CharToCheck)
Counter++;
}
return Counter;
}
This will cause inValue to be true while inside fields. E.g. pass '"' as fieldDelimiter to ignore everything between "...". Just note that this won't handle escaped " (like "" or \"). You'd have to add such handling yourself.
Instead of checking the resulting string (the cake) you should check the fields (ingredients) before you concatenate (mix) them. That would give you the change to do something constructive (escaping/replacing) and throwing an exception only as a last resort.
In general, "," are legal in .csv fields, as long as the string fields are quoted. So internal "," should not be a problem, but the quotes may well be.