I've tried googling this and looking at questions/answers on here but I'm not having much luck.
I have a list of values that I've already put into an array by splitting on the commas (","), but now I need to split on the colons (":"). I am at a loss for how to do this, everything I've tried so far hasn't working and I can't figure out how to fix it.
string AdditionalData = "Name: John, Age: 43, Location: California";
string[] firstData = AdditionalData.Split(',');
The above code is how far I've gotten - this works - but no matter what I try I can't figure out how to split the data on the colon. Basically, I'm looking to take the array "firstData" and make that into a new array.
Any help would be appreciated and apologies for the simplicity of the question, I'm new to this!
Side note: This is part of an asp.net mvc project if that is of any help, the tag was removed. the results are also displayed as a web page, not in the console.
Iterate each array item using a foreach loop.
foreach(string dataString in firstData)
{
string[] temp = dataString.Split(':')
//do something with the new array here
}
I guess this is what you want, but I'm not sure.
var secondData = firstData.Select(str => str.Split(':'));
Related
I'm sure this isn't as complicated as I'm making it.
I have a string that follows the following pattern:
#,"value"#,"next value"#,"next value" . . .
I need to parse out the number/value pairs in order to use the data in my application.
Here is a sample of a return:
0,"120"1,""10,"298630427"29,"577015971830"30,"SG MSNA "33,"A1"34,"4625"35,"239"36,"2105"37,"2759"60,"15"112,"0"
To complicate matters the string can contain newline characters (\r,\n, or \r\n).
I can handle that by simply removing the newlines with a few string.replace calls.
I would ultimately like to parse the data into key/value pairs. I just can't seem to get my mind unto the right path.
I apologize if this is trivial but I've been pulling 18+ hours days for two months trying to meet a deadline and my brain is shot. Any assistance or guidance in the right direction will be most appreciated.
var numVal=Regex.Matches(input,#"\"([^\"]+)\"(\d+)")
.Cast<Match>()
.Select(x=>new
{
num=x.Groups[2].Value,
value=x.Groups[1].Value
});
Now you can iterate over numVal
foreach(var nv in numVal)
{
nv.num;
nv.value;
}
If you're going straight to key value pairs, you might be able to use LINQ to make your life easier. You'll have to be aware of and handle cases where you don't match the key/value format. However, you might be able to achieve it using something like this.
var string_delimiter = new [] { ',' };
var kvp_delimiter = new[] { "\"" };
var dictionary = string_value.Split(string_delimiter)
.Select(kvp_string => kvp_string.Split(kvp_delimiter, StringSplitOptions.RemoveEmptyEntries))
.ToDictionary(kvp_vals => kvp_vals.First(), kvp_vals => kvp_vals.Last());
One of the things I really value from this community is learning ways to do things in two lines that would normally take me twenty. In that spirit, I've done my best to take some string parsing down from about a dozen lines to three. But I feel like there's someone out there who wants to show me how this is actually a mess. Just for my own edification, is there a cleaner way to do the following? Could it all be done in one line?
string getThis = "<add key=\"messageFilter\" value=\"";
string subStr = strFile.Substring(strFile.IndexOf(getThis) + getThis.Length);
string[] igPhrases = subStr.Substring(0, subStr.IndexOf(";\"")).Split(';');
UPDATE
Thanks for the quick responses! Really helpful examples AND good advice with a minimum of snark. :) Fewer lines is not the same thing as clean and elegant, and reducing lines may actually make the code worse.
Let me rephrase the question.
I've got an XML doc that has the following line: <add key="messageFilter" value="Out of Office AutoReply;Automatic reply;"/>. This doc tells our automated ticketing system not to create tickets from emails that have those phrases in the subject line. Otherwise, we get an endless loop.
I'm working on a small program that will list phrases already included, and then allow users to add new phrases. If we notice that a new autoreply message is starting to loop through the system, we need to be able to add the language of that message to the filter.
I don't work a lot with XML. I like Sperske's solution, but I don't know how to make it dynamic. In other words, I can't put the value in my code. I need to find the key "messageFilter" and then get all the values associated with that key.
What I've done works, but it seems a little cumbersome. Is there a more straightforward way to get the key values? And to add a new one?
A slightly different one liner (split for readability):
System.Xml.Linq.XDocument
.Parse("<add key='messageFilter' value='AttrValue'/>")
.Root
.Attribute("value")
.Value
Outputs:
AttrValue
To address the updated question you could turn all of your <add> nodes into a dictionary (borrowing from Pako's excellent answer, and using a slightly longer string):
var keys = System.Xml.Linq.XDocument
.Parse("<keys><add key='messageFilter' value='AttrValue'/><add key='userFilter' value='AttrValueUser'/></keys>")
.Descendants("add")
.ToDictionary(r => r.Attribute("key").Value, r => r.Attribute("value").Value);
This lets you access your keys like so:
keys["messageFilter"] == "AttrValue"
keys["userFilter"] == "AttrValueUser"
It has been answered already, but for future readers - if you want to parse bigger XML, with root and many add nodes, you may need to use something slightly different.
string xmlPart = "<add key=\"messageFilter\" value=\"\" />";
string xml = "<root>" + xmlPart + "</root>";
var x = XDocument.Parse(xmlPart, LoadOptions.None);
var attributes1 = x.Descendants("add").Select(n => n.Attributes());
var attributes2 = x.Descendants("add").SelectMany(n => n.Attributes());
This will get you IEnumerable<IEnumerable<XAttribute>> (see attributes1) or IEnumerable<XAttribue> (see attributes2). Second option will simply flatten results - all attributes will be held in one collection, no matter from which node they came from.
Of course nothing stops you to filter XAttributes by name or some other criteria - it all up to you!
one ugly line:
string[] igPhrases = strFile.Substring(strFile.IndexOf(getThis) + ("<add key=\"messageFilter\" value=\"").Length).Substring(0, strFile.Substring(strFile.IndexOf("<add key=\"messageFilter\" value=\"") + ("<add key=\"messageFilter\" value=\"").Length).IndexOf(";\"")).Split(';');
I seem to be having a very weird problem and I really have no idea what's going on. This is the source code I'm trying to debug
StorageFile file = await roamingFolder.GetFileAsync(filename);
string text = await FileIO.ReadTextAsync(file);
string[] shows = text.Split(new[] { ":?;" }, StringSplitOptions.None);
List<show> showslist = new List<show>();
foreach (string splitshow in shows)
{
string[] show1 = splitshow.Split(new[] { ",?;" }, StringSplitOptions.None);
episode = show1[0];
name = show1[1];
showslist.Add(new show { name = name, episode = episode });
}
Output.ItemsSource = showslist;
The weird thing is that the list is shown only if I put Output.ItemsSource = showslist; inside of the foreach loop but not when it's outside and I really don't understand why it's not. I mean elements of the list have already been added to it haven't they??
Have tried many different methods and most of them even if they did show the list data had many different problems that are too messy to fix.
Anyway appreciate any hint or help, thank you.
I'll bet that your data isn't exactly correct. I think one of the later/last entries is throwing an exception and it's being swallowed higher up in your code (or not being reported to your logger/UI). It never completes the foreach loop and exits the method before you can assign your data source.
I would guess that your second split, one of the entries does not actually contain your delimiter ,?; so the show1 array is only of length 1 and does not contain a "name" entry. When you try to access show1[1], it throws an IndexOutOfRangeException.
As an aside, might I suggest that you investigate using simpler delimiters, or better yet, utilize some form of XML (or JSON, or other) serialization for reading your data.
EDIT: I see from your posted code sample in your comments, that the issue is the last entry. Given hlj,?;lljhjh:?;hhmm,?;drr:?;oo,?;hello:?;ff,?;ff:?;, your first String.Split operation on :?; will yield an empty string as the last entry. Thus when you try to perform your second split against ,?; it splits against empty and returns an array with a single entry of String.Empty. When you hit show1[1] the exception is thrown.
If you change your first split to use StringSplitOptions.RemoveEmptyEntries it should eliminate the empty entry:
string[] shows = text.Split(new[] { ":?;" }, StringSplitOptions.RemoveEmptyEntries);
If you like, you can add a check like if (show1.Length == 2) then you can avoid bad data (but perhaps you would prefer to report that so you can fix it). If your program is writing this bad data itself, perhaps you should make a couple quick unit tests to ensure that you're always writing/reading valid data.
I am currently working on an address selector for a checkout process, this currently has a function that adds a comma after all fields that are found on the check out like this.
This is done using,
ddl.Items.Add(new ListItem(string.Join(", ", lines.ToArray()), address.ID.ToString()));
This is fine until you add a name in, which is a must have so they may use their account to delivery to a different person in the case of gifts or if you wish to order something and have someone else sign for the product. I wish for my first/last name to not have a comma between them, however... I can't simply do this by not adding a comma on the first two fields as there is many cases in which a name would not be entered on the delivery address.
This is how it displays currently
I was thinking the best way to do this was to split the name into a separate string and then the rest of the address into another, add the commas in and then rejoin the strings into one.
If anyone could think of a better way to do this, please share your ideas.
1 You can also use
string.Concat(lines.ToArray()).Replace(" ",",");
2 Or iterate with foreach and build stringBuilder
I have used this method,
StringBuilder fullName = new StringBuilder();
List<string> lines = new List<string>();
if (!string.IsNullOrEmpty(address.Name))
fullName.AppendFormat("{0} ", address.Name);
if (!string.IsNullOrEmpty(address.Name1))
fullName.AppendFormat("{0} ", address.Name1);
if (!string.IsNullOrEmpty(address.Name2))
fullName.Append(address.Name2);
if (!string.IsNullOrEmpty(fullName.ToString()))
lines.Add(fullName.ToString());
String = String.Replace(","," ");
or
String = String.Replace(","," ");
This will do what you want.
Using C# (VS 2010 Express) I read the contents of a text file into a string. The string is rather long but reliably broken up by "\t" for tabs and "\r\n" for carriage returns/newlines.
The tabs indicate a new column of data, and new line indicates a new row of data.
I want to create an array or List of dimensions (X)(Y) such that each spot in the array can hold 1 row of data from the text file, and all of the Y columns contained in that 1 row ("\t" means a new column of data, and "\r\n" means a new row of data").
To make things simple let's say my text has 10 rows of data, and 2 columns. I'd like to create an array or List or whatever you think is best to store the data. How do I do this? Thanks.
This is the code that I used to read the data in the text file into a string:
// Read the file as one string.
System.IO.StreamReader myFile = new System.IO.StreamReader("f:\\data.txt");
string myString = myFile.ReadToEnd();
Just as is (you already have a string with everything):
str.Split(new string[]{"\r\n"}, StringSplitOptions.None)
.Select(s => s.Split('\t'));
Gives you an IEnumerable<string[]> producing variantes like list of list, array of array and so on just needs the suitable ToArray() or ToList() etc.
However, if you can deal with each line one at a time, you can be better off with something that lets you do so:
public IEnumerable<string[]> ReadTSV(TextReader tr)
{
using(tr)
for(string line = tr.ReadLine(); line != null; line = tr.ReadLine())
yield return line.Split('\t');
}
Then you only use as much memory as each line needs. We could go further and change the reading to emit each individual cell one at a time, but this is normally enough to read files of several hundred MB in size, with reasonable efficiency.
Edit based on comments on question:
If you really wanted to, you could get a List<string[]> from:
var myFile = new StreamReader("f:\\data.txt");
var list = ReadTSV(myFile).ToList();
Alternatively, change the line yield return line.Split('\t'); to yield return line.Split('\t'); and you get a List<List<string>>.
However, if possible then work on the results directly, rather than putting it into a list first:
var myFile = new StreamReader("f:\\data.txt");
var chunks = ReadTSV(myFile);
foreach(var chunk in chunks)
{
DoSometingOnAChunk(chunk[0], chunk[1]);
}
It'll use less memory, and get started faster rather than pausing to read the whole thing first. Code like this can merrily work its way through gigabytes without complaint.
String.Split
http://msdn.microsoft.com/en-us/library/system.string.split.aspx
File.ReadLines(sourceFilePath)
.Select(line => line.Split('\t'))
.ToArray();
This will read the file and create a list of string arrays for you
List<string[]> rows= File.ReadLines("PathToFile")
.Select(line=>line.Split('\t')).ToList();
If you want string[][] version, simply use ToArray(); instead of ToList(); at the end.
The TextFieldParser is a fantastic class for dealing with text based delimited files. You can provide it a file, a delimiter (in this case "\t") and it will provide a method to get the next line of values (as a string array).
It has advantages over a simple Split in the general case as it can handle comments, quoted fields, escaped delimiters, etc. You may or may not have such cases, but having all of those awkward edge cases handled pretty much for free is rather nice.
var result = contents.Split("\r\n".ToArray(), StringSplitOptions.RemoveEmptyEntries).Select(s => {
s.Split('\t').ToList();
}).ToList();
result will be a List<List<String>>.