List and foreach - c#

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.

Related

Parsing this special format file

I have a file that is formatted this way --
{2000}000000012199{3100}123456789*{3320}110009558*{3400}9876
54321*{3600}CTR{4200}D2343984*JOHN DOE*1232 STREET*DALLAS TX
78302**{5000}D9210293*JANE DOE*1234 STREET*SUITE 201*DALLAS
TX 73920**
Basically, the number in curly brackets denotes field, followed by the value for that field. For example, {2000} is the field for "Amount", and the value for it is 121.99 (implied decimal). {3100} is the field for "AccountNumber" and the value for it is 123456789*.
I am trying to figure out a way to split the file into "records" and each record would contain the record type (the value in the curly brackets) and record value, but I don't see how.
How do I do this without a loop going through each character in the input?
A different way to look at it.... The { character is a record delimiter, and the } character is a field delimiter. You can just use Split().
var input = #"{2000}000000012199{3100}123456789*{3320}110009558*{3400}987654321*{3600}CTR{4200}D2343984*JOHN DOE*1232 STREET*DALLAS TX78302**{5000}D9210293*JANE DOE*1234 STREET*SUITE 201*DALLASTX 73920**";
var rows = input.Split( new [] {"{"} , StringSplitOptions.RemoveEmptyEntries);
foreach (var row in rows)
{
var fields = row.Split(new [] { "}"}, StringSplitOptions.RemoveEmptyEntries);
Console.WriteLine("{0} = {1}", fields[0], fields[1]);
}
Output:
2000 = 000000012199
3100 = 123456789*
3320 = 110009558*
3400 = 987654321*
3600 = CTR
4200 = D2343984*JOHN DOE*1232 STREET*DALLAS TX78302**
5000 = D9210293*JANE DOE*1234 STREET*SUITE 201*DALLASTX 73920**
Fiddle
This regular expression should get you going:
Match a literal {
Match 1 or more digts ("a number")
Match a literal }
Match all characters that are not an opening {
\{\d+\}[^{]+
It assumes that the values itself cannot contain an opening curly brace. If that's the case, you need to be more clever, e.g. #"\{\d+\}(?:\\{|[^{])+" (there are likely better ways)
Create a Regex instance and have it match against the text. Each "field" will be a separate match
var text = #"{123}abc{456}xyz";
var regex = new Regex(#"\{\d+\}[^{]+", RegexOptions.Compiled);
foreach (var match in regex.Matches(text)) {
Console.WriteLine(match.Groups[0].Value);
}
This doesn't fully answer the question, but it was getting too long to be a comment, so I'm leaving it here in Community Wiki mode. It does, at least, present a better strategy that may lead to a solution:
The main thing to understand here is it's rare — like, REALLY rare — to genuinely encounter a whole new kind of a file format for which an existing parser doesn't already exist. Even custom applications with custom file types will still typically build the basic structure of their file around a generic format like JSON or XML, or sometimes an industry-specific format like HL7 or MARC.
The strategy you should follow, then, is to first determine exactly what you're dealing with. Look at the software that generates the file; is there an existing SDK, reference, or package for the format? Or look at the industry surrounding this data; is there a special set of formats related to that industry?
Once you know this, you will almost always find an existing parser ready and waiting, and it's usually as easy as adding a NuGet package. These parsers are genuinely faster, need less code, and will be less susceptible to bugs (because most will have already been found by someone else). It's just an all-around better way to address the issue.
Now what I see in the question isn't something I recognize, so it's just possible you genuinely do have a custom format for which you'll need to write a parser from scratch... but even so, it doesn't seem like we're to that point yet.
Here is how to do it in linq without slow regex
string x = "{2000}000000012199{3100}123456789*{3320}110009558*{3400}987654321*{3600}CTR{4200}D2343984*JOHN DOE*1232 STREET*DALLAS TX78302**{5000}D9210293*JANE DOE*1234 STREET*SUITE 201*DALLASTX 73920**";
var result =
x.Split('{',StringSplitOptions.RemoveEmptyEntries)
.Aggregate(new List<Tuple<string, string>>(),
(l, z) => { var az = z.Split('}');
l.Add(new Tuple<string, string>(az[0], az[1]));
return l;})
LinqPad output:

Splitting large string in c# and adding values in it to a List

I have a string as shown below
string names = "<?startname; Max?><?startname; Alex?><?startname; Rudy?>";
is there any way I can split this string and add Max , Alex and Rudy into a separate list ?
Sure, split on two strings (all that consistently comes before, and all that consistently comes after) and specify that you want Split to remove the empties:
var r = names.Split(new[]{ "<?startname; ", "?>" }, StringSplitOptions.RemoveEmptyEntries);
If you take out the RemoveEmptyEntries it will give you a more clear idea of how the splitting is working, but in essence without it you'd get your names interspersed with array entries that are empty strings because split found a delimiter (the <?...) immediately following another (the ?>) with an empty string between the delimiters
You can read the volumes of info about this form of split here - that's a direct link to netcore3.1, you can change your version in the table of contents - this variant of Split has been available since framework2.0
You did also say "add to a separate list" - didn't see any code for that so I guess you will either be happy to proceed with r here being "a separate list" (an array actually, but probably adequately equivalent and easy to convert with LINQ's ToList() if not) or if you have another list of names (that really is a List<string>) then you can thatList.AddRange(r) it
Another Idea is to use Regex
The following regex should work :
(?<=; )(.*?)(?=\s*\?>)

Click a listbox item and display textfile text in labels

I'm getting stuck clicking a listbox item (the items in my listbox is .txt files in a folder) and displaying the values in the .txt file.
the values in the .txt files are all seperated with a "," and I want each Split item to display in labels on my form.
my file path is: System.AppDomain.CurrentDomain.BaseDirectory + "data"
my .txt file names are the names of the selected item in my listbox.
I have a basic idea of what should happen, but I have no clue how to express this in code.
My Code:
private void custList_MouseClick(object sender, MouseEventArgs e)
{
string foldr = System.AppDomain.CurrentDomain.BaseDirectory + "data";
string file = custList.SelectedIndex.ToString();
}
Thanx in advance
Before i go on answering this question, please read How to ask. This will help you better understand this community and ask better questions(to get better support).
Next on, do some research. From a first glance, it looks like you are asking someone to do the homework for you. Anyways, i am not here to be tough on you. I will point you out a few things. Try to understand them and utilize them.
Note that even though it may seem as such but i am not a fan of spoon-feeding so be sincere and do your research.
Let's start with your text file. As you mentioned, it contains values. C#, being a versatile & mature language has a lot of functions,methods,classes pre-built to help boost your programming experience. Such a method is ReadAllText, a part of the File class. In the simplest words, this method opens a text file, reads it, returns it's value. A sample use of this method could be :
string TextFromFile = File.ReadAllText(File_Path_Goes_Here);
Moving on... Your text file has multiple values separated by comma(,). In such cases, each value needs to read as a separate value upon retrieving or displaying. So, you want a List of the values, end of story. In C#, you have a wide range of generic lists to use from. As the values in the text file are simple strings, you can use a List<string> in this regard. A basic usage example of List<string> would be :
List<string> TestList1 = new List<string>();
TestList1.Add("First Value"); TestList1.Add("Second Value");
///or
List<string> TestList1 = new List<string>(){ "First Value", "Second Value" };
In your particular case, File.ReadAllLines is worth an example. The method opens a text file, reads it, closes it. Of course it returns the value read from the text file, as an array. So, when passing values to the generic list, you can simply make use of this method. Example :
...... new List<string>(File.ReadAllLines(Path_Of_File_Goes_Here));
The only twist here is that the values in your text file are in a line(maybe) and also are separated by comma. So, what do you think should work here ? ReadAllText or ReadAllLines ? I will leave it upto you.
Once values are read from the file, we can make use of the Split function to split the values upon each occurrence of a comma(,). A simple example :
List<string> NameList = "Josh,Riley".Split(',').ToList<string>();
And last but not the least, the headline of the question which doesn't seem to have anything to do with the post itself, here's what you can take a look at :
Control Click Event
ListBox.GetItemText
Tip: The SelectedItem property of the ListBox class returns or sets the selected item of a listbox.
I hope this has been helpful. Do pay attention to all that's mentioned above. It may be a bit hard to follow up with at first, but remember, Consistency is the hallmark of the unimaginative.
....Yeah, that's not my quote. Gotcha!
I don't know where you want to show the values of your text file, so I will just provide you what you need to retrieve those informations.
To get values from your file:
public string[] GetValues()
{
string[] values;
using(StreamReader sr = new StreamReader(Path.Combine(foldr, file))
{
string text = sr.ReadToEnd();
values = text.Split(',');
}
return values;
}
Then you can show them using an array:
public void Main()
{
string[] values = GetValues();
foreach(var value in values)
{
Console.WriteLine(value);
}
}
Hope this helps.

Splitting an array into another array?

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(':'));

How do I break a string into an array (or List) in C#?

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>>.

Categories