why does it appear a blank space between to string concatened c# - c#

public string completeHour(string theTime)
{
string total="";
string[] timeArray = theTime.Split(new[] { ":" }, StringSplitOptions.None);
string h = timeArray[0];
string i = timeArray[1];
string j = timeArray[2];
MessageBox.Show(h + "+" + i + "+" + j);
if (h == " " || i == " " || j == " ")
{
if (h == " ")
{
h = "00";
total = (String.Concat("00",theTime)).Trim();
MessageBox.Show(total);
}
else if (i == " ")
{
i = "00";
total = timeArray[0] + i + timeArray[2];
//MessageBox.Show("m-=" + total);
}
//else if (j == "")
//{
// j = "00";
// theTime = timeArray[0] + timeArray[1] + j;
// MessageBox.Show("s-=" + theTime);
//}
}
return total;
}
Why total is 00 :52:04 (for instance) and not 00:52:04 that was supposed to be?

If you'd like to make sure there are no leading or trailing white characters, you could call
string h = timeArray[0].Trim();
And then instead of checking the value against " ", you could compare it to String.Empty or call h.IsNullOrEmpty().
However I'd strongly recommend you to use simpler approach, using a DateTime object.
DateTime timeObject;
DateTime.TryParse(theTime, out timeObject);
and then just work with Hour, Minute and Second properties. This way you get away from custom parsing and make your code more object-oriented, thus easier to read, instead of juggling multiple string objects.

Best way to avoid this is using Trim() when assigning value to total in following two lines:
total = (String.Concat("00",theTime.Trim())).Trim();
.
.
.
total = timeArray[0].trim() + i + timeArray[2].Trim();

Although I was using a MaskedTextBox I didn't define a custom mask so, anywhere (I think) the system assumed that 'theTime' was the type of DateTime.
So, the result of String.Concat("00",theTime) was '00 :32:99', for instance.
I´ve solved it by using the variables h, i and j instead of theTime.
Using a DateTime variable was not appropriated because I want to allow the user to insert NULL values for the hours or for the minutes.

Related

C# EPPlus databar conditional formatting with solid fill color

I am generating excel reports that involves several columns that are percentage data. Since the reports are for presentation purposes I want to make them look nice by formatting the percentage data with databars with solid fill. Somehow this proves to be extremely difficult as there is no direct setting in EPPlus for solid fill for databar but nevertheless I have arrived at the answer that is in this post:
Inconsistent appearance between manual and coded versions of solid databar and databar minimum value
However no matter how hard I try to edit the code for my application I only have one column that end up with solid fill with the rest being gradient. Even though I changed the node in the question to a nodelist such as below:
var cfNodes = xdoc.SelectNodes("/default:worksheet/default:conditionalFormatting/default:cfRule", nsm);
foreach(XmlNode cfNode in cfNodes)
{
cfNode.AppendChild(extLstCf);
}
and also for the worksheet elements:
var wsNodes = xdoc.SelectNodes("/default:worksheet", nsm);
foreach(XmlElement wsNode in wsNodes)
{
wsNode.AppendChild(extLstWs);
}
I also tried playing around with the xml changing the <sqref> parameter but that still doesn't cover all my databar columns. I think there has to be something that I can change in the xml to accomplish what I want but I don't know what to look for...
Ok guys It took me a few days but I finally figured it out. There might be a simpler way to do this but so far this is how I got it working for me:
A worksheet xml extension list node need to be appended at the worksheet level node which includes the number data bar elements that your worksheet contains, and each of them needs to have gradient = 0 for solid fill I. For example my worksheet contains two data bars so mine looks like this:
var extLstWs = xdoc.CreateNode(XmlNodeType.Element, "extLst", xdoc.DocumentElement.NamespaceURI);
extLstWs.InnerXml = #"<ext uri=""{78C0D931-6437-407d-A8EE-F0AAD7539E65}""
xmlns:x14=""http://schemas.microsoft.com/office/spreadsheetml/2009/9/main"">
<x14:conditionalFormattings>
<x14:conditionalFormatting xmlns:xm=""http://schemas.microsoft.com/office/excel/2006/main"">
<x14:cfRule type=""dataBar"" id=""{3F3F0E19-800E-4C9F-9CAF-1E3CE014ED86}"">
<x14:dataBar minLength=""0"" maxLength=""100"" gradient=""0"">
<x14:cfvo type=""num"">
<xm:f>0</xm:f>
</x14:cfvo>
<x14:cfvo type=""num"">
<xm:f>100</xm:f>
</x14:cfvo>
<x14:negativeFillColor rgb=""FFFF0000""/><x14:axisColor rgb=""FF000000""/>
</x14:dataBar>
</x14:cfRule>
<xm:sqref>A1:A20</xm:sqref>
</x14:conditionalFormatting>
<x14:conditionalFormatting xmlns:xm=""http://schemas.microsoft.com/office/excel/2006/main"">
<x14:cfRule type=""dataBar"" id=""{3F3F0E19-800E-4C9F-9CAF-1E3CE014ED86}"">
<x14:dataBar minLength=""0"" maxLength=""100"" gradient=""0"">
<x14:cfvo type=""num"">
<xm:f>0</xm:f>
</x14:cfvo><x14:cfvo type=""num"">
<xm:f>200</xm:f>
</x14:cfvo><x14:negativeFillColor rgb=""FFFF0000""/>
<x14:axisColor rgb=""FF000000""/>
</x14:dataBar>
</x14:cfRule>
<xm:sqref>B1:B20</xm:sqref>
</x14:conditionalFormatting>
</x14:conditionalFormattings>
</ext>";
var wsNode = xdoc.SelectSingleNode("/default:worksheet", nsm);
wsNode.AppendChild(extLstWs);
Notice how I got two subnodes of <x14:conditionalFormattings> in there, one for each databar.
Secondly another extension list for conditional formatting rule nodes need to be appended under the <cfRule> node, also one for each databar. I was able to use a foreach loop to find all the databars in my worksheet and append the same xml to each of them like below:
var cfNodes = xdoc.SelectNodes("/default:worksheet/default:conditionalFormatting/default:cfRule", nsm);
foreach (XmlNode cfnode in cfNodes)
{
var extLstCfNormal = xdoc.CreateNode(XmlNodeType.Element, "extLst", xdoc.DocumentElement.NamespaceURI);
extLstCfNormal.InnerXml = #"<ext uri=""{B025F937-C7B1-47D3-B67F-A62EFF666E3E}""
xmlns:x14=""http://schemas.microsoft.com/office/spreadsheetml/2009/9/main"">
<x14:id>{3F3F0E19-800E-4C9F-9CAF-1E3CE014ED86}</x14:id></ext>";
cfnode.AppendChild(extLstCfNormal);
}
After doing the above I was finally able to show all my databars with solid fill.
This is my version how to make databars solid fill for those who fail to apply Aowei Xu's solution (like me...).
public static Random Rnd = new Random();
public static string GenerateXlsId()
{
//{29BD882A-B741-482B-9067-72CC5D939236}
string id = string.Empty;
for (int i = 0; i < 32; i++)
if (Rnd.NextDouble() < 0.5)
id += Rnd.Next(0, 10);
else
id += (char)Rnd.Next(65, 91);
id = id.Insert(8, "-");
id = id.Insert(13, "-");
id = id.Insert(18, "-");
id = id.Insert(23, "-");
return id;
}
public static void FixDatabarsAtWorksheet(OfficeOpenXml.ExcelWorksheet eworksheet)
{
System.Xml.XmlNodeList databars = eworksheet.WorksheetXml.GetElementsByTagName("dataBar");
if (databars.Count > 0)
{
string conditional_formattings_str = string.Empty;
for (int i = 0; i < databars.Count; i++)
{
string temp_databar_id = GenerateXlsId();
databars[i].ParentNode.InnerXml += #"<extLst>
<ext uri=""{B025F937-C7B1-47D3-B67F-A62EFF666E3E}"" xmlns:x14=""http://schemas.microsoft.com/office/spreadsheetml/2009/9/main"">
<x14:id>{" + temp_databar_id + #"}</x14:id>
</ext>
</extLst>";
//--
string temp_sqref = databars[i].ParentNode.ParentNode.Attributes["sqref"].Value;
string left_type = string.Empty;
string left_val = string.Empty;
string right_type = string.Empty;
string right_val = string.Empty;
string color = string.Empty;
Color databar_fill_color = Color.Empty;
Color databar_border_color = Color.Empty;
for (int j = 0; j < databars[i].ChildNodes.Count; j++)
if (databars[i].ChildNodes[j].LocalName == "cfvo" && databars[i].ChildNodes[j].Attributes["type"] != null)
{
if (string.IsNullOrEmpty(left_type))
left_type = databars[i].ChildNodes[j].Attributes["type"].Value;
else if (string.IsNullOrEmpty(right_type))
right_type = databars[i].ChildNodes[j].Attributes["type"].Value;
if (databars[i].ChildNodes[j].Attributes["val"] != null)
if (string.IsNullOrEmpty(left_val))
left_val = databars[i].ChildNodes[j].Attributes["val"].Value;
else if (string.IsNullOrEmpty(right_val))
right_val = databars[i].ChildNodes[j].Attributes["val"].Value;
}
else if (databars[i].ChildNodes[j].LocalName == "color")
{
color = databars[i].ChildNodes[j].Attributes["rgb"].Value;
int argb = Int32.Parse(color, System.Globalization.NumberStyles.HexNumber);
databar_fill_color = Color.FromArgb(argb);
databar_border_color = Color.FromArgb(255,
databar_fill_color.R - 50 < 0 ? databar_fill_color.R + 50 : databar_fill_color.R - 50,
databar_fill_color.G - 50 < 0 ? databar_fill_color.R + 50 : databar_fill_color.G - 50,
databar_fill_color.B - 50 < 0 ? databar_fill_color.R + 50 : databar_fill_color.B - 50);
}
string temp_conditional_formatting_template = #"<x14:conditionalFormatting xmlns:xm=""http://schemas.microsoft.com/office/excel/2006/main"">
<x14:cfRule type=""dataBar"" id=""{" + temp_databar_id + #"}"">
<x14:dataBar minLength=""" + (string.IsNullOrEmpty(left_val) ? "0" : left_val) + "\" maxLength=\"" + (string.IsNullOrEmpty(right_val) ? "100" : right_val) + "\" gradient=\"0\" " + (databar_border_color.IsEmpty ? string.Empty : "border = \"1\"") + ">";
temp_conditional_formatting_template += Environment.NewLine + "<x14:cfvo type=\"" + (left_type.ToLower() == "min" ? "autoMin" : left_type) + "\" />";
temp_conditional_formatting_template += Environment.NewLine + "<x14:cfvo type=\"" + (right_type.ToLower() == "max" ? "autoMax" : right_type) + "\" />";
if (!databar_border_color.IsEmpty)
temp_conditional_formatting_template += Environment.NewLine + "<x14:borderColor rgb=\"" + BitConverter.ToString(new byte[] { databar_border_color.A, databar_border_color.R, databar_border_color.G, databar_border_color.B }).Replace("-", "") + "\" />";
temp_conditional_formatting_template += Environment.NewLine + #"</x14:dataBar>
</x14:cfRule>
<xm:sqref>" + temp_sqref + #"</xm:sqref>
</x14:conditionalFormatting>";
conditional_formattings_str += temp_conditional_formatting_template;
}
databars[0].ParentNode.ParentNode.ParentNode.InnerXml += #"<extLst>
<ext uri=""{78C0D931-6437-407d-A8EE-F0AAD7539E65}"" xmlns:x14=""http://schemas.microsoft.com/office/spreadsheetml/2009/9/main"">
<x14:conditionalFormattings>" + conditional_formattings_str + #"
</x14:conditionalFormattings>
</ext>
</extLst>";
}
}
Such pain for such small thing... Gwa-a-a-a-a-ar-r-r-r!
P.S. MS, I hate you for XmlElements skipping prefix value when inserting them into parent nodes!
P.S.2. This makes any other conditional formatting to vanish... don't know why... OMG!

C# Writing to a csv file where a value has a string literal inside of it

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

Why is my logic not adding the quotes back to the CSV File for the columns after the First one?

I am using hashmaps to store CSVFile1 and compare it to CSVFile2. CSVFile1 has a column of customers to remove while CSVFile2 has all of the completed data (which has more then 1 column and that is why I am only comparing dataArray2[0]). Once I compare I only rewrite the files that are NOT in the CSVFile1 to a file called CSVFileFinal.
The issue is that some of the data has commas inside of fields and when I read the file it take them out once I try and rewrite. My goal is to rewrite the data with the quotes back around the commas in the fields which I "split" at.
I have managed to get the First column (the most important one) to split and replace the quotes perfectly! But for whatever reason my second loop is messing up and not checking the columns after that correctly. I believe it is simply the placing of my code.
This is the logical statement/placement in question:
if (dataArray2[i].Contains(","))
{
string x = "\"" + dataArray2[i] + "\"";
record = x;
}
I know the logic works because if you look at my entire source code; the code posted works for the first column and works in the 2nd IF statement for If i == 0 meaning if it's the 1st columns. But how or where do I place that to work for the others afterward?
Can anyone help figure out where to place this for the following columns?
It should be a simple copy and pasting of the code I have but I've been unable to figure it out. Thank you!
int count = 0;
while (!CSVFile2.EndOfData)
{
if (!badCustomers.ContainsKey(dataArray2[0]))
{
String record = null;
for(int i = 0; i < dataArray2.Length; i++)
{
if(i == 0)
{
if (dataArray2[i].Contains(","))
{
string x = "\"" + dataArray2[i] + "\"";
record = x;
}
else
record = dataArray2[i];
} else
{
record = record + "," + dataArray2[i];
}
}
count++;
if( count % 50 == 0)
{
Console.WriteLine(count);
}
output.WriteLine(record);
}
dataArray2 = CSVFile2.ReadFields();
}
The above code works but does not consider the later columns after the first one to replace this quotes- this code is what should fix the ones after the first column but for whatever reason it does not. Why?
if (!badCustomers.ContainsKey(dataArray2[0]))
{
String record = null;
for(int i = 0; i < dataArray2.Length; i++)
{
if(i == 0)
{
if (dataArray2[i].Contains(","))
{
string x = "\"" + dataArray2[i] + "\"";
record = x;
}
else
record = dataArray2[i];
} else
{
if (dataArray2[i].Contains(","))
{
string x = "\"" + dataArray2[i] + "\"";
record = x;
}
else
record = record + "," + dataArray2[i];
}
}
What I believe you are asking is for this:
int count = 0;
while (!CSVFile2.EndOfData)
{
if (!badCustomers.ContainsKey(dataArray2[0]))
{
String record = String.Empty;
for(int i = 0; i < dataArray2.Length; i++)
{
if (dataArray2[i].Contains(","))
{
string x = "\"" + dataArray2[i] + "\"";
record += x;
}
else
{
record += dataArray2[i];
}
if (i < dataArray.Length -1)
{
record += ",";
}
}
count++;
if( count % 50 == 0)
{
Console.WriteLine(count);
}
output.WriteLine(record);
}
dataArray2 = CSVFile2.ReadFields();
}
This loops through each line from the input, adding quotes around commas. You may have to tweak it to meet your final needs, but this should be a start.
The reason it was only ever doing it for your first column is the if(i == 0). This means the code would only ever execute for the first iteration (your first column).

Better way of doing it - GetFiles - c#

I'm trying to get all files in a directory but I want them associated with numbers. Now, I have this:
string[] ficheiro = Directory.GetFiles(#"C:\Users\David\Documents\Jogos\Jogos de emuladores\Roms GB\", "*.gba");
{
Console.WriteLine ("F1" + " - " + Path.GetFileNameWithoutExtension (ficheiro[0]));
}
Console.ReadKey ();
When I reach 10 files I will have a shortcut to flip a page to get more files (10 per page). I will list all files by hand. Like this:
Console.WriteLine ("F2" + " - " + Path.GetFileNameWithoutExtension (ficheiro[1]));
Console.WriteLine ("F3" + " - " + Path.GetFileNameWithoutExtension (ficheiro[2]));
Is there a better way of doing it?
You need to use a loop. You cannot do all of them "by hand" because you do not necessarily know how many there are.
var files = Directory.GetFiles(#"C:\Your\Directory\Path", "*.gba");
var count = 0;
foreach (var file in files)
{
if (count % 10 == 0 && count != 0)
{
Console.ReadLine();
}
count++;
Console.WriteLine("F{0} - {1}", count, Path.GetFileNameWithoutExtension(file));
}
Console.ReadLine();
You can iterate through the array with a for-loop :
string[] ficheiros = Directory.GetFiles(#"C:\Users\David\Documents\Jogos\Jogos de emuladores\Roms GB\", "*.gba");
for (int i = 0; i < ficheiros.Length; i++)
{
Console.WriteLine("F{0} - {1}", i + 1, Path.GetFileNameWithoutExtension(ficheiros[i]));
}
Console.ReadKey();
The key is to identify the repeating part and extract a pattern from it :
//only these changed V V
Console.WriteLine ("F2" + " - " + Path.GetFileNameWithoutExtension (ficheiro[1]));
Console.WriteLine ("F3" + " - " + Path.GetFileNameWithoutExtension (ficheiro[2]));
// just replace them and put it inside an appropriate loop, in this case a for-loop
for(int i = 0; i < ficheiro.Length; i++)
Console.WriteLine ("F" + (i+1) + " - " + Path.GetFileNameWithoutExtension (ficheiro[i]));
int i = 0;
var ficheiro = from s in Directory.GetFiles(#"C:\temp\", "*.*")
select ("F"+ i++ + "-" + s);

CSV Validation in C# - Making sure each row has the same number of commas

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.

Categories