Split string and put in DataTable, find second index number - c#

I have a question about split string and put it in DataTable. How can i know if the second array is a string or number?
I have a text with many string like this:
text : ...
abc 123 def 1 \"ok lo\" ;
abc def 1 \"ok lo\" ;
...
array2:
tmpList[0] = abc
tmpList[1] = 123
tmpList[2] = def
tmpList[3] = 1 \"ok lo\"
array1:
tmpList[0] = abc
tmpList[1] = def
tmpList[2] = 1 \"ok lo\
To find all strings startwith abc i did:
StreamReader fin = new StreamReader(userSelectedFilePath1);
string tmp = "";
while ((tmp = fin.ReadLine()) != null)
{
if (tmp.StartsWith("abc "))
{
var tmpList1 = tmp.Split(new[] { '"' }).SelectMany((s, i) =>
{
if (i % 2 == 1) return new[] { s };
return s.Split(new[] { ' ', ';', ',' }, StringSplitOptions.RemoveEmptyEntries);
}).ToList();
table.Rows.Add(new object[] { tmpList1[0], tmpList1[1], tmpList1[2], tmpList1[3]});
}
}
With this code i can find String startswith abc, split and put in DataTable. How can i know if the second index is a string or int? Becasuse with what i did i have a error with second index and it splits not correcly. I think about if(tmp.StartsWith(abc NUMBER?)) else do the code above

When you do String.Split(), all of the values in the array will be Strings as well, so in your example for ABC:
tmpList[1] = 123 // this is incorrect as the value is an int
This should be:
tmpList[1] = "123" // value is a string
Then what you can do is try to cast the value to an int, and if it fails, you know it's not an int:
int number;
bool result = Int32.TryParse(tmpList[1], out number);
if (result) {
// your code for if the value is a number
}
else {
// your code for if the value is not a number
}
Code example copied from here.

Related

Convert String to Int in a Single Line C#

I have a string input like:
1 3 4 1 2
I want to Sum the number into integer. I tried the following code:
using System;
public class Program
{
public static void Main()
{
string input2 = "1 3 4 1 1";
string value2 = input2.Replace(" ", "+");
int val = int.Parse(value2);
Console.WriteLine(val);
}
}
But it is not correct. Does anyone have an idea for this?
Thank you.
You can try Split the initial string (input2) into items, TryParse them into corresponding int bvalues and then Sum them with a help of Linq:
using System.Linq;
...
int val = value2
.Split(' ', StringSplitOptions.RemoveEmptyEntries)
.Sum(item => int.TryParse(item, out int value) ? value : 0);
Here all invalid items (i.e. items which can't be parsed as an integer) are ignored (we turn them into 0). You may want an exception thrown in this case:
using System.Linq;
...
int val = value2
.Split(' ', StringSplitOptions.RemoveEmptyEntries)
.Sum(item => int.Parse(item));
Finally, your code amended (we can use an old trick with DataTable.Compute):
using System.Data;
...
string input2 = "1 3 4 1 1";
string formula = input2.Replace(' ', '+');
using (DataTable table = new DataTable())
{
int val = Convert.ToInt32(table.Compute(formula, null));
Console.WriteLine(val);
}
You can Split input2 with a space character into an array then use system.linq.enumerable.sum()
string input2 = "1 3 4 1 1";
var result= input2.Split(' ').Sum(x=> int.Parse(x));

What's an easy way to give a string a value based on the characters it contains in C#?

I'm trying to get a sum value based on what characters a string contains. The character values are determined by me and are somewhat arbitrary ('A' = 1, 'B' = 4, 'C' = 2, etc.). For example, if string s = "ABC" then int value = 7 because 1 + 4 + 2 = 7. What would be an efficient way to write this in C#?
Right now my code looks like this:
//Declare variables
string name = JOHN
int i = 0;
int nameValue = 0;
string temp = "";
string[] nameArray;
//Convert name to string array so I can use String.Contains() to check what letters are in name
foreach (char c in name)
{
temp += c.ToString();
temp += ".";
}
temp = temp.Remove(temp.Length - 1, 1);
nameArray = temp.Split('.');
//Determine nameValue by iterating through nameArray and checking each string
foreach (string s in nameArray)
{
if (nameArray[i].Contains('A')) { nameValue += 1 }
else if (nameArray[i].Contains('B')) { nameValue += 4 }
else if (nameArray[i].Contains('C')) { nameValue += 2 }
else if (nameArray[i].Contains('D')) { nameValue += 3 }
.
.
.
else if (nameArray[i].Contains('Y')) { nameValue += 7 }
else if (nameArray[i].Contains('Z')) { nameValue += 5 }
i++;
}
Console.WriteLine(nameValue);
I changed the string to a string array because I have names that have repeating letters (i.e. Jill), and I want to give every letter in the name a value. If I used String.Contains() without separating every letter, it would only count repeating letters once, I think.
I feel like there has to be a better way than doing all that string manipulation and using a separate conditional statement for every letter in the alphabet, but I couldn't find anything. Thanks.
If you want to map consequent characters (say, 'A'..'Z') to integer values, I suggest using array:
using System.Linq;
...
int[] map = new int[] {
//TODO: put corresponding integer values starting from 'A'
4, 2, 3
};
...
s = "ABC";
int sum = s.Sum(c => map[c - 'A']);
In general case, if you want to map arbitrary symbols, you can use dictionary:
using System.Linq;
...
Dictionary<char, int> map = new Dictionary<char, int>() {
//TODO: put all required pairs here
{'A', 4},
{'B', 2},
{'C', 1},
{'#', -123},
};
...
s = "ABC";
// if there's no map (e.g. for '*'), we assume the value being 0
int sum = s.Sum(c => map.TryGetValue(c, out int v) ? v : 0);
http://www.asciitable.com/
you will see that capitol A is 65
string str = "Hi there";
foreach(char c in str.ToUpper())
{
value += ((int)c) - 64;
}

C# Curly Brace in String.Format [duplicate]

I have 3 strings. The first set of strings are:
"1.0536"
"2.1"
"2"
The second is something like:
"Round"
"Square"
"Hex"
And the last are:
"6061-T6"
"T351"
"ASF.3.4.5"
I need to combine the three strings together with identical spacing in between each string. I can't use \t for tabbing as after I combine the strings, I send them to an Access Database.
When I combine the strings they look like:
"1.0536 Round 6061-T6"
"2.1 Square T351"
"2 Hex ASF.3.4.5"
I would really like them to look like this with the same exact amount of spacing in between each string:
"1.0536 Round 6061-T6"
"2.1 Square T351"
"2 Hex ASF.3.4.5"
How can I do this with C#?
You can use advanced features of string.Format:
string.Format("{0,-10}{1,-10}{2}", ...)
You can do the same thing by writing str.PadRight(10)
If you know the maximum lengths of each column then do the following:
String result = String.Format("{0} {1} {2}", strCol1.PadRight(10), strCol2.PadRight(9), strCol3.PadRight(9));
To make life easier, utility methods:
Usage
var data = new[] {
new[] { "ID", "NAME", "DESCRIPTION" },
new[] { "1", "Frank Foo", "lorem ipsum sic dolor" },
new[] { "2", "Brandon Bar", "amet forthrightly" },
new[] { "3", "B. Baz", "Yeehah!" }
};
var tabbedData = EvenColumns(20, data);
var tabbedData2 = string.Join("\n", EvenColumns(20, false, data)); // alternate line separator, alignment
Results
ID NAME DESCRIPTION
1 Frank Foo lorem ipsum sic dolor
2 Brandon Bar amet forthrightly
3 B. Baz Yeehah!
ID NAME DESCRIPTION
1 Frank Foolorem ipsum sic dolor
2 Brandon Bar amet forthrightly
3 B. Baz Yeehah!
Code
public string EvenColumns(int desiredWidth, IEnumerable<IEnumerable<string>> lists) {
return string.Join(Environment.NewLine, EvenColumns(desiredWidth, true, lists));
}
public IEnumerable<string> EvenColumns(int desiredWidth, bool rightOrLeft, IEnumerable<IEnumerable<string>> lists) {
return lists.Select(o => EvenColumns(desiredWidth, rightOrLeft, o.ToArray()));
}
public string EvenColumns(int desiredWidth, bool rightOrLeftAlignment, string[] list, bool fitToItems = false) {
// right alignment needs "-X" 'width' vs left alignment which is just "X" in the `string.Format` format string
int columnWidth = (rightOrLeftAlignment ? -1 : 1) *
// fit to actual items? this could screw up "evenness" if
// one column is longer than the others
// and you use this with multiple rows
(fitToItems
? Math.Max(desiredWidth, list.Select(o => o.Length).Max())
: desiredWidth
);
// make columns for all but the "last" (or first) one
string format = string.Concat(Enumerable.Range(rightOrLeftAlignment ? 0 : 1, list.Length-1).Select( i => string.Format("{{{0},{1}}}", i, columnWidth) ));
// then add the "last" one without Alignment
if(rightOrLeftAlignment) {
format += "{" + (list.Length-1) + "}";
}
else {
format = "{0}" + format;
}
return string.Format(format, list);
}
Specific to the Question
// for fun, assume multidimensional declaration rather than jagged
var data = new[,] {
{ "1.0536", "2.1", "2" },
{ "Round", "Square", "Hex" },
{ "6061-T6", "T351", "ASF.3.4.5" },
};
var tabbedData = EvenColumns(20, Transpose(ToJaggedArray(data)));
with Transpose:
public T[][] Transpose<T>(T[][] original) {
// flip dimensions
var h = original.Length;
var w = original[0].Length;
var result = new T[h][];
for (var r = 0; r < h; r++) {
result[r] = new T[w];
for (var c = 0; c < w; c++)
{
result[r][c] = original[c][r];
}
}
return result;
}
And multidimensional arrays (source):
public T[][] ToJaggedArray<T>(T[,] multiArray) {
// via https://stackoverflow.com/questions/3010219/jagged-arrays-multidimensional-arrays-conversion-in-asp-net
var h = multiArray.GetLength(0);
var w = multiArray.GetLength(1);
var result = new T[h][];
for (var r = 0; r < h; r++) {
result[r] = new T[w];
for (var c = 0; c < w; c++) {
result[r][c] = multiArray[r, c];
}
}
return result;
}
I know this has long since been answered, but there is a new way as of C# 6.0
string[] one = new string[] { "1.0536", "2.1", "2" };
string[] two = new string[] { "Round", "Square", "Hex" };
string[] three = new string[] { "1.0536 Round 6061-T6", "2.1 Square T351", "2 Hex ASF.3.4.5" };
for (int i = 0; i < 3; i++) Console.WriteLine($"{one[i],-10}{two[i],-10}{three[i],-10}");
The $"{one[i],-10}{two[i],-10}{three[i],-10}" is the new replacement for string.format . I have found it very useful in many of my projects. Here is a link to more information about string interpolation in c# 6.0:
https://learn.microsoft.com/en-us/dotnet/csharp/tutorials/string-interpolation
Use String.Format("{0,10}", myString)
Where 10 is the number of characters you want
To do it more dynamically you could do something like this: (hardcoding ahead!)
int padding = 3;
int maxCol0width = "Hello World!".Length;
int maxCol1width = "90.345".Length;
int maxCol2width = "value".Length;
string fmt0 = "{0,-" + (maxCol0width + padding) + "}";
string fmt1 = "{1,-" + (maxCol1width + padding) + "}";
string fmt2 = "{2,-" + (maxCol2width + padding) + "}";
string fmt = fmt0 + fmt1 + fmt2;
Console.WriteLine(fmt, "Hello World!", 90.345, "value");
Console.WriteLine(fmt, "Hi!", 1.2, "X");
Console.WriteLine(fmt, "Another", 100, "ZZZ");
You will of course need to figure out your max word widths by looping through each column's values. Also the creation of the format string could be significantly cleaned up and shortened.
Also note that you will need to use a non-proportional font for display, otherwise your columns will still not line up properly. Where are you displaying this data? There may be better ways of getting tabular output.

Get specific data from a line of text

I need to extract the following data (in bold) from the text line below and put it into a data grid;
PERS tooldata t_rrt_ja03579:=[TRUE,[[-39.643,-0.001,1025.49],[0.382684,-0.000130001,-0.923889,0.000120001]],[200.9,[-88.1,-12.6,359.7],[1,0,0,0],29.347,50.927,18.261]];
This line is read from a file. I have managed to trim the line so it gets rid of the "PERS tooldata" and whitespaces and it leaves me with the tool name. I have it bound to data in a datagrid elsewhere in the code which is step 1 complete.
My question is how can I extract the values in bold individually and place them in to double data declarations? The first block of values (-39.643,-0.001,1025.49) is a X,Y,Z co-ordinate value and the second (0.382684,-0.000130001,-0.923889,0.000120001) are Q1,Q2,Q3,Q4.
Below is how i done the name
private void AutoFillToolData(object sender, RoutedEventArgs e)
{
// Gives user option to auto populate datagrid
var AutoFillToolResult = MessageBox.Show("Do you want to auto populate fields?", "Tool Data", MessageBoxButton.YesNo);
if (AutoFillToolResult == MessageBoxResult.Yes)
{
// User directs application to the specified file
System.Windows.Forms.FolderBrowserDialog folderBrowser = new System.Windows.Forms.FolderBrowserDialog();
if (folderBrowser.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
// Application looks for specific file and removes unwanted data
string robotBackupPath = folderBrowser.SelectedPath;
string allDataPath = robotBackupPath + #"\RAPID\TASK1\SYSMOD\ALL_DATA.sys";
string[] tLines = File.ReadAllLines(allDataPath);
List<string> toolDataLines = new List<string>();
foreach (string tLine in tLines)
{
if (tLine.Contains("PERS tooldata") && !tLine.StartsWith("!"))
{
if (tLine.Contains("tToolChanger")) continue;
if (tLine.Contains("tPointer")) continue;
if (tLine.Contains("tHome")) continue;
toolDataLines.Add(tLine);
}
}
foreach (string line in toolDataLines)
{
// Gets the name of the tool
ToolData toolData = GetToolNameFromLine(line);
// Puts the tool name in the DataGrid
TCPData.Add(toolData);
}
}
}
}
private ToolData GetToolNameFromLine(string line)
{
// Removes white space at the beggining of line in txt file
ToolData tooldata = new ToolData();
string[] spaceSplit = line.Trim().Split(' ');
string values = spaceSplit[2];
// Gets Tool Name
int colonLocation = values.IndexOf(":");
tooldata.ToolName = values.Substring(0, colonLocation);
return tooldata;
}
If all the samples you'll have follow the same pattern, extracting those values does not seem difficult:
//First we get all the string after the :=
string tooldata = line.Substring(data.IndexOf(":=") + 2) ;
//Split the string by [
string[] tooldataArray = tooldata.Split(new char[] { '[' }, StringSplitOptions.RemoveEmptyEntries);
//the second and the third strings are what we are interested in
string xyzValue = tooldataArray[1].Replace(']' ,' ');
string Q1234value = tooldataArray[2].Replace(']', ' ');
If after this you want to get the individual parameters, just splitting by , would do.
Edit
This would extract all the values you want to arrays of double:
string tooldata = data.Substring(data.IndexOf(":=") + 2) ;
string[] tooldataArray = tooldata.Split(new char[] { '[' }, StringSplitOptions.RemoveEmptyEntries);
double[] xyzValue = tooldataArray[1].Replace(']' ,' ')
.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
.Select(s => double.Parse(s, CultureInfo.InvariantCulture))
.ToArray();
double[] Q1234value = tooldataArray[2].Replace(']', ' ')
.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
.Select(s => double.Parse(s, CultureInfo.InvariantCulture))
.ToArray();

How can I change code inside a <pre></pre> and change it into a table without losing empty lines?

I have been using some code that takes as input HTML and then changes
code inside a <pre> ... </pre> and makes it into a table. Here's the
code:
public static string FormatCode(this string content)
{
var data1 = content
.Split(new[] { "<pre>", "</pre>" }, StringSplitOptions.None);
var data2 = data1
.Select((s, index) =>
{
string s1 = index % 2 == 1 ? string.Format("{0}{2}{1}",
"<table class='code'>", "</table>", SplitJoin(s)) : s;
return s1;
});
var data3 = data2.Where(s => !string.IsNullOrEmpty(s));
var data4 = string.Join("\n", data3);
return data4;
}
private static string SplitJoin(string content)
{
IEnumerable<String> code =
content.Split(new[] { '\n' }, StringSplitOptions.RemoveEmptyEntries)
.Select((line, index) =>
string.Format("<tr><td>{0}</td><td><pre><code>{1}</code></pre></td></tr>\n",
(index + 1).ToString("D2"), HttpUtility.HtmlEncode(line)));
return string.Join("", code) + "\n";
}
If my HTML is like this:
<p>xxx</p><pre>public enum XXX {
private String command1;
private String command2;
}
}</pre>
It converts this into:
<table class="code"><tbody>
<tr><td>01</td><td><p>xxx</p></td></tr>
<tr><td>02</td><td><pre>public enum XXX {</pre></td></tr>
<tr><td>03</td><td><pre> private String command1;</pre></td></tr>
<tr><td>04</td><td><pre> private String command2;</pre></td></tr>
<tr><td>05</td><td><pre>}</pre></td></tr>
</tbody></table>
The problem is that empty line inside a <pre> are not output. Can someone help me
by telling me how I could change my code so that when there is an empty line in the
<pre> then it still outputs a row with a correct row number and something with an
Update: Following a suggested answer I tried making a change to my function to this:
IEnumerable<String> code =
// content.Split(new[] { '\n' }, StringSplitOptions.RemoveEmptyEntries)
content.Split(new[] { '\n' }, StringSplitOptions.None)
.Select((line, index) =>
string.Format("<tr><td>{0}</td><td><pre><code>{1}</code></pre></td></tr>\n",
(index + 1).ToString("D2"), HttpUtility.HtmlEncode(line)));
return string.Join("", code) + "\n";
However I still do not see the empty lines in the tables.
StringSplitOptions.RemoveEmptyEntries removes empty entries when splitting on the newline character. If you don't want to remove empty entries, don't use this option.

Categories

Resources