C# separating data within a line from a text file - c#

I have a data file
Name; LastName; EurosCents;
Name2; LastName2; EurosCents2;
(for example:
John; Smith; 4,20;
Josh; Peck; 6,50;
)
I need to read the data and then do some further work with it... Is there any way to read the lines and save them? As the only way to read from a text file is to read the entire line at once.

var lst = File.ReadAllLines(yourFilePath).Select(x => new
{
FirstName = x.Split(';')[0]
LastName = x.Split(';')[1]
Value = decimal.Parse(x.Split(';')[2])
}).ToList();
use
lst[7].FirstName = "xxx";
Console.WriteLine(lst[2].Value);
etc...

The File API provide multiple options for reading files. Below is a possible way to proceed:
foreach(var line in File.ReadAllLines(path))
{
var splitted = line.Split(';');
var name = splitted.ElementAtOrDefault(0);
var lastName = splitted.ElementAtOrDefault(1);
var cents = Decimal.Parse(splitted.ElementAtOrDefault(2));
}

Parsing will be very easy if you are comfortable using LINQ.
Below line can get you the file in a hierarchical structure.
var theselines = File.ReadLines(#"C:\Test.txt").Select(l => l.Split(','));
You can see the result of above line by debugging.
Later you can have any logic to get the required data from each line without using foreach loop.
var Data = theselines.Select(l => new
{
id = l.Where(t => t.Contains("01")).FirstOrDefault(),
Price = l.Where(t => t.Contains(",")).FirstOrDefault(),
Firstname= l[0],
lastname = l[1]
});

Providing that data itself (both names and cents) can't contain ; in order to get
items from the comma separated values you can just split:
var data = File
.ReadLines(#"C:\MyData.csv")
// .Skip(1) // <- in case you have caption to skip
.Select(line => line.Split(';'))
.Select(items => new {
Name = items[0],
LastName = items[1],
EuroCents = decimal.Parse(items[2]) //TODO: check type and its format
});
//.ToArray(); // <- if you want to materialize as, say, an array
Then you can use it
foreach (var item in data) {
if (item.EuroCents > 10) {
...
}
}

the simple code to read whole file is as follows
string[] test(string path)
{
System.IO.StreamReader sr = new System.IO.StreamReader(path);
string[] str = sr.ReadToEnd().Split(';');
sr.Close();
return str;
}

Related

How to filter values read from a text file

I want to get a couple of values from a textfile in C#. Example:
1.sex=male
1.name=barack
1.lastname=obama
1.age = 55
2.sex=female
2.name= kelly
2.lastname=clinton
2.age = 24
3.sex = male
3.firstname= mike
3.lastname= james
3.age= 19
I only want to get all the "name", "lastname" and ages from the textFile, not the "sex". How can I filter this? I have tried something like this, but it only shows 1 value.
var list = new List<string>();
var text = File.ReadAllLines(#"C:\Users\Jal\Desktop\Test.text");
foreach (var s in text)
{
if (s.Contains("Name"))
{
if (s.Contains("Name"))
{
var desc = s.Substring(s.IndexOf("=") + 1);
list.Add(desc);
ListView.Items.Add(desc);
}
}
}
I found this code on Stack Overflow, but it doesn't get all of the values I want.
var names = new List<string>();
var lastnames = new List<string>();
var text = File.ReadAllLines(#"C:\Users\Jal\Desktop\Test.text");
foreach (var s in text)
{
if (s.Contains("lastname"))
{
var lastname = s.Substring(s.IndexOf("=") + 1);
lastnames.Add(lastname);
continue;
}
if (s.Contains("name"))
{
var name = s.Substring(s.IndexOf("=") + 1);
names.Add(name);
continue;
}
}
And in same way you can add another properties.
s.Contains("Name") won't ever be true on this case because it's case-sensitive, and your string in the file is "name".
Try using s.Contains("name")
But you would be better off using a Regex for this kind of thing.

Using array to replace string

I have a two arrays i have taken from a csv file, i want to check my current output for the first array and output the second array, eg
"Hello, LOL" would output "Hello, Laugh out loud"
i have used
var reader = new StreamReader(File.OpenRead(#filelocation"));
List<string> listA = new List<string>();
List<string> listB = new List<string>();
while (!reader.EndOfStream)
{
var line = reader.ReadLine();
var values = line.Split(',');
listA.Add(values[0]);
listB.Add(values[1]);
}
The arrays are stored and have the correct information in them, i just don't know how to check a string from the first list and change it to the second.
You should use a Dictionary for this operation instead of List. In addition, you could use File.ReadAllLines to read all lines in a file instead of looping.
// I replace your code with linq
Dictionary<string, string> dictionary =
File.ReadAllLines("#filelocation").Select(l => l.Split(',')).ToDictionary(k =>
k[0], v => v[1]);
string input = "Hello, LOL" ;
var thekey = dictionary.Keys.FirstOrDefault(k => input.Contains(k));
if (thekey != null) // Replacement was found
{
input = input.Replace(thekey, dictionary[thekey]);
}
// Should print Hello, Laugh out loud
Console.WriteLine(input) ;

C# Read text file and print out in to a table

I'm trying to read a text file and print out into a table.
I want the output to be this
But now I having different output
var column1 = new List<string>();
var column2 = new List<string>();
var column3 = new List<string>();
using (var rd = new StreamReader(#"C:\test.txt"))
{
while (!rd.EndOfStream)
{
var splits = rd.ReadLine().Split(';');
column1.Add(splits[0]);
column2.Add(splits[1]);
column3.Add(splits[2]);
}
}
Console.WriteLine("Date/Time \t Movie \t Seat");
foreach (var element in column1) Console.WriteLine(element);
foreach (var element in column2) Console.WriteLine(element);
foreach (var element in column3) Console.WriteLine(element);
You can use Linq to construct a convenient structure (e.g. List<String[]>) and then print out all the data wanted:
List<String[]> data = File
.ReadLines(#"C:\test.txt")
//.Skip(1) // <- uncomment this to skip caption if the csv has it
.Select(line => line.Split(';').Take(3).ToArray()) // 3 items only
.ToList();
// Table output (wanted one):
String report = String.Join(Environment.NewLine,
data.Select(items => String.Join("\t", items)));
Console.WriteLine(report);
// Column after column output (actual one)
Console.WriteLine(String.Join(Environment.NewLine, data.Select(item => item[0])));
Console.WriteLine(String.Join(Environment.NewLine, data.Select(item => item[1])));
Console.WriteLine(String.Join(Environment.NewLine, data.Select(item => item[2])));
EDIT: if you want to choose the movie, buy the ticket etc. elaborate the structure:
// Create a custom class where implement your logic
public class MovieRecord {
private Date m_Start;
private String m_Name;
private int m_Seats;
...
public MovieRecord(DateTime start, String name, int seats) {
...
m_Seats = seats;
...
}
...
public String ToString() {
return String.Join("\t", m_Start, m_Name, m_Seats);
}
public void Buy() {...}
...
}
And then convert to conventinal structure:
List<MovieRecord> data = File
.ReadLines(#"C:\test.txt")
//.Skip(1) // <- uncomment this to skip caption if the csv has it
.Select(line => {
String items[] = line.Split(';');
return new MovieRecord(
DateTime.ParseExact(items[0], "PutActualFormat", CultureInfo.InvariantCulture),
items[1],
int.Parse(items[2]));
}
.ToList();
And the table output will be
Console.Write(String.Join(Envrironment.NewLine, data));
Don't use Console.WriteLine if you want to add a "column". You should also use a single List<string[]> instead of multiple List<string>.
List<string[]> allLineFields = new List<string[]>();
using (var rd = new StreamReader(#"C:\test.txt"))
{
while (!rd.EndOfStream)
{
var splits = rd.ReadLine().Split(';');
allLineFields.Add(splits);
}
}
Console.WriteLine("Date/Time \t Movie \t Seat");
foreach(string[] line in allLineFields)
Console.WriteLine(String.Join("\t", line));
In general you should use a real csv parser if you want to parse a csv-file, not string methods or regex.
You could use the TextFieldParser which is the only one available in the framework directly:
var allLineFields = new List<string[]>();
using (var parser = new Microsoft.VisualBasic.FileIO.TextFieldParser(#"C:\test.txt"))
{
parser.Delimiters = new string[] { ";" };
parser.HasFieldsEnclosedInQuotes = false; // very useful
string[] lineFields;
while ((lineFields = parser.ReadFields()) != null)
{
allLineFields.Add(lineFields);
}
}
You need to add a reference to the Microsoft.VisualBasic dll to your project.
There are other available: Parsing CSV files in C#, with header
You could attempt to solve this in a more Object-Orientated manner, which might make it a bit easier for you to work with:
You can declare a simple class to represent a movie seat:
class MovieSeat
{
public readonly string Date, Name, Number;
public MovieSeat(string source)
{
string[] data = source.Split(';');
Date = data[0];
Name = data[1];
Number = data[2];
}
}
And then you can read in and print out the data in a few lines of code:
// Read in the text file and create a new MovieSeat object for each line in the file.
// Iterate over all MovieSeat objets and print them to console.
foreach(var seat in File.ReadAllLines(#"C:\test.txt").Select(x => new MovieSeat(x)))
Console.WriteLine(string.Join("\t", seat.Date, seat.Name, seat.Number));

line number while querying with linq

I am using a stream reader to read a text file and then using Linq for retrieving the information
String fileContent = prodFileStreamReader.ReadToEnd();
var mydata = from con in fileContent.Split('$').Select(x => x.Trim())
where !String.IsNullOrEmpty(con)
select new BaseSegment
{
dataID = con.Substring(0, con.IndexOf('#')),
dataElms = con.Split('#').ToArray(),
dataCon = con,
lineNumber =
};
I would also like to get the line number. I tried using Index but I was not able to. How to query to get the index and assign it to lineNumber?
Try using the select that projects index into each item, as given in this msdn article: http://msdn.microsoft.com/en-us/library/bb534869.aspx
In your case something like this (not tested):
var mydata = fileContent.Split('$')
.Select(x => x.Trim())
.Where(con => !String.IsNullOrEmpty(con))
.Select((con, index) => new
{
dataID = con.Substring(0, con.IndexOf('#')),
dataElms = con.Split('#').ToArray(),
dataCon = con,
lineNumber = index
});
For starters, I would not read the file in as a big string. Use methods that could process it in small chunks. Use File.ReadLines() for example to read through the file line by line. It will be easier to get line numbers this way and much more efficient than reading it all at once only to split it up again.
const string filePath = ...;
var myData =
from pair in File.ReadLines(filePath)
.Select((LineNumber, Line) => new { LineNumber, Line })
where ...
select new BaseSegment
{
...
Line = pair.Line,
LineNumber = pair.LineNumber,
};
p.s., You should stick to the usual C# naming conventions. Public properties of your classes should use PascalCasing, not camelCasing and should not be abbreviated.
The code you use to process the content looks awkward. It could probably be improved if I knew what the files looked like. I'll leave that out until you could show us how it is.
How about this?
var animalList = from a in animals
select new { Animal = a, Index = animals.IndexOf(a) };
or in your case...
Index = fileContent.IndexOf(con)
if this whole data is going in myData then you can use the index directly from the myData.
Try This:
String fileContent = prodFileStreamReader.ReadToEnd();
var mydata = from con in fileContent.Split('$').Select(x => x.Trim())
where !String.IsNullOrEmpty(con)
select new BaseSegment
{
dataID = con.Substring(0, con.IndexOf('#')),
dataElms = con.Split('#').ToArray(),
dataCon = con,
lineNumber = Array.IndexOf(fileContent.Split('$').Select(x => x.Trim(),con)
};
Array.IndexOf(yourArrey,the string you looking for); -> will return the index in the arrey.
you can try something like this
long index = 0;
var xElementsAndNodes = from xmlElement in elementsColl
select new
{
Index = index += 1,
....
}

C#: What's an efficient way of parsing a string with one delimiter through ReadLine() of TextReader?

C#: What's an efficient way to parse a string with one delimiter for each ReadLine() of TextReader?
My objective is to load a list of proxies to ListView into two columns (Proxy|Port) reading from a .txt file. How would I go upon splitting each readline() into the proxy and port variables with the delimiter ":"?
This is what I've got so far,
public void loadProxies(string FilePath)
{
string Proxy; // example/temporary place holders
int Port; // updated at each readline() loop.
using (TextReader textReader = new StreamReader(FilePath))
{
string Line;
while ((Line = textReader.ReadLine()) != null)
{
// How would I go about directing which string to return whether
// what's to the left of the delimiter : or to the right?
//Proxy = Line.Split(':');
//Port = Line.Split(':');
// listview stuff done here (this part I'm familiar with already)
}
}
}
If not, is there a more efficient way to do this?
string [] parts = line.Split(':');
string proxy = parts[0];
string port = parts[1];
You could split them this way:
string line;
string[] tokens;
while ((Line = textReader.ReadLine()) != null)
{
tokens = line.Split(':');
proxy = tokens[0];
port = tokens[1];
// listview stuff done here (this part I'm familiar with already)
}
it's best practise to use small letter names for variables in C#, as the other ones are reserved for class / namespace names etc.
How about running a Regex on the whole file?
var parts=
Regex.Matches(input, #"(?<left>[^:]*):(?<right>.*)",RegexOptions.Multiline)
.Cast<Match>()
.Where(m=>m.Success)
.Select(m => new
{
left = m.Groups["left"],
right = m.Groups["right"]
});
foreach(var part in parts)
{
//part.left
//part.right
}
Or, if it's too big, why not Linqify the ReadLine operation with yielding method?
static IEnumerable<string> Lines(string filename)
{
using (var sr = new StreamReader(filename))
{
while (!sr.EndOfStream)
{
yield return sr.ReadLine();
}
}
}
And run it like so:
var parts=Lines(filename)
.Select(
line=>Regex.Match(input, #"(?<left>[^:]*):(?<right>.*)")
)
.Where(m=>m.Success)
.Select(m => new
{
left = m.Groups["left"],
right = m.Groups["right"]
});
foreach(var part in parts)
{
//part.left
//part.right
}
In terms of efficiency I expect you'd be hard-pressed to beat:
int index = line.IndexOf(':');
if (index < 0) throw new InvalidOperationException();
Proxy = line.Substring(0, index);
Port = int.Parse(line.Substring(index + 1));
This avoids the array construction / allocation associated with Split, and only looks as far as the first delimited. But I should stress that this is unlikely to be a genuine performance bottleneck unless the data volume is huge, so pretty-much any approach should be fine. In fact, perhaps the most important thing (I've been reminded by the comment below) is to suspend the UI while adding:
myListView.BeginUpdate();
try {
// TODO: add all the items here
} finally {
myListView.EndUpdate();
}
You might want to try something like this.
var items = File.ReadAllText(FilePath)
.Split(new[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries)
.Select(line => line.Split(':'))
.Select(pieces => new {
Proxy = pieces[0],
Port = int.Parse(pieces[1])
});
If you know that you won't have a stray newline at the end of the file you can do this.
var items = File.ReadAllLines(FilePath)
.Select(line => line.Split(':'))
.Select(pieces => new {
Proxy = pieces[0],
Port = Convert.ToInt32(pieces[1])
});

Categories