How to parse a text file? - c#

Basically I need someone to help me or show me the code that will allow me to read a name and a price from a file i have called c1.txt.
This is what i already have.
TextReader c1 = new StreamReader("c1.txt");
if (cse == "c1")
{
string compc1;
compc1 = c1.ReadLine();
Console.WriteLine(compc1);
Console.WriteLine();
compcase = compc1;
compcasecost = 89.99;
}
also how to select a line to read from a text document would be great.

You haven't told us the format of the text file. I am going to assume the following:
Milk|2.69
Eggs|1.79
Yogurt|2.99
Soy milk|3.79
You also didn't specify the output. I am going to assume the following:
Name = Milk, Price = 2.69
Name = Eggs, Price = 1.79
Name = Yogurt, Price = 2.99
Name = Soy milk, Price = 3.79
Then the following will read such a file and produce the desired output.
using(TextReader tr = new StreamReader("c1.txt")) {
string line;
while((line = tr.ReadLine()) != null) {
string[] fields = line.Split('|');
string name = fields[0];
decimal price = Decimal.Parse(fields[1]);
Console.WriteLine(
String.Format("Name = {0}, Price = {1}", name, price)
);
}
}
If your separator is different then you need to change the parameter '|' to the method String.Split (invoked on the instance of String named line as line.Split('|')).
If your format needs to be different then you need to play with the line
String.Format("Name = {0}, Price = {1}", name, price)
Let me know if you have any questions.

You can also try using a parsing helper class as a starting point, such as the one described at http://www.blackbeltcoder.com/Articles/strings/a-text-parsing-helper-class.

static void ReadText()
{
//open the file, read it, put each line into an array of strings
//and then close the file
string[] text = File.ReadAllLines("c1.txt");
//use StringBuilder instead of string to optimize performance
StringBuilder name = null;
StringBuilder price = null;
foreach (string line in text)
{
//get the name of the product (the string before the separator "," )
name = new StringBuilder((line.Split(','))[0]);
//get the Price (the string after the separator "," )
price = new StringBuilder((line.Split(','))[1]);
//finally format and display the result in the Console
Console.WriteLine("Name = {0}, Price = {1}", name, price);
}
It gives the same results as #Jason's method, but I think this is an optimized version.

Related

I want to read text and replace parts that are surrounded by signals

I have a chunk of text for example
string OriginalText = "Hello my name is <!name!> and I am <!age!> years old";
I'm struggling to write a function that I can enter this text into and it will return the same string except with the values surrounded by the Tags "<!" and "!>" to be replace with actual values. I have some code written but don't know how to progress any further.
if(OriginalText.Contains("<!")) //Checks if Change is necessary
{
string[] Total = OriginalText.Split(
new Char[] { '<', '!' },
StringSplitOptions.RemoveEmptyEntries);
if(Total[1].Contains("!>")) //Checks if closing tag exists
{
string ExtTag = Total[1].Split(
new Char[] { '<', '!' },
StringSplitOptions.RemoveEmptyEntries)[0];
ExtData.Add(Total[1].Split(
new Char[] { '<', '!' },
StringSplitOptions.RemoveEmptyEntries)[0]);
return Total[1];
}
}
The desired output would be
"Hello my name is James and I am 21 years old"
I am currently getting this text from a database and so this functions purpose would be to read that text and input the correct information.
Edit: Figured out how to do it so I'm going to include it below however I'm writing this in a program called mattersphere so there will reference to functions that aren't standard c#, I will put comments next to them explain what they do.
private string ConvertCodeToExtData(string OriginalText) //Accepts text with the identifying symbols as placeholders
{
string[] OriginalWords = OriginalText.Split(' '); //Creates array of individual words
string ConvertedText = string.Empty;
int Index = 0;
foreach(string OriginalWord in OriginalWords) //Go through each word in the array
{
if(OriginalWord.Substring(0,1).Equals("<") && OriginalWord.Substring(OriginalWord.Length-1 ,1).Equals(">")) //Checks if Change is necessary
{
string[] ExtDataCodeAndSymbols = OriginalWord.Substring(1, OriginalWord.Length-2).Split('.'); //Decided to create 4 different parts inbetween the <> tags it goes Symbol(e.g £, $, #) . area to look . field . symbol //separates the Code Identifier and the ExtData and Code
try
{
foreach(ExtendedData ex in this.CurrentSession.CurrentFile.ExtendedData) //Search through All data connected to the file, Extended data is essentially all the data from the database that is specific to the current user
{
if(ex.Code.ToLower() == ExtDataCodeAndSymbols[1].ToLower())
{
OriginalWords[Index] = ExtDataCodeAndSymbols[0] + ex.GetExtendedData(ExtDataCodeAndSymbols[2]).ToString() + ExtDataCodeAndSymbols[3]; //Replace code with new data
break;
}
}
}
catch (Exception ex)
{
System.Windows.Forms.MessageBox.Show("Extended Data Field " + ExtDataCodeAndSymbols[1] + "." + ExtDataCodeAndSymbols[2] + " Not found, please speak to your system administrator"); //Handles Error if Ext Data is not found
}
}
Index++;
}
foreach(string Word in OriginalWords)
{
ConvertedText += Word + " "; //Adds all words into a single string and adds space
}
ConvertedText.Remove(ConvertedText.Length -1, 1); //Removes Last Space
return ConvertedText;
}
The text goes in "Hello my name is <.Person.name.> and I have <£.Account.Balance.> in my bank account" and comes out "Hello my name is James and I have £100 in my bank account"
The symbols are optional but the "." are necessary as they are used to split the strings early in the function
If you have to use <!...!> placeholders, I suggest regular expressions:
using System.Text.RegularExpressions;
...
string OriginalText = "Hello my name is <!name!> and I am <!age!> years old";
Dictionary<string, string> substitutes =
new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase) {
{ "name", "John" },
{ "age", "108"},
};
string result = Regex
.Replace(OriginalText,
#"<!([A-Za-z0-9]+)!>", // let placeholder contain letter and digits
match => substitutes[match.Groups[1].Value]);
Console.WriteLine(result);
Outcome:
Hello my name is John and I am 108 years old
Assuming you are stuck with that format, and assuming you know the list of fields ahead of time, you can compose a dictionary of replacement strings and, well, replace them.
//Initialize fields dictionary
var fields = new Dictionary<string, string>();
fields.Add("name", "John");
fields.Add("age", "18");
//Replace each field if it is found
string text = OriginalText;
foreach (var key in fields.Keys)
{
string searchFor = "<!" + key + "!>";
text = text.Replace(searchFor, fields[key]);
}
If the values for the replacement fields come from a domain object, you could just iterate over the properties using reflection:
class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
class Program
{
const string OriginalText = "Hello my name is <!name!> and I am <!age!> years old";
public static void Main()
{
var p = new Person();
p.Age = 18;
p.Name = "John";
//Initialize fields dictionary
var fields = new Dictionary<string, string>();
foreach (var prop in typeof(Person).GetProperties(BindingFlags.Public | BindingFlags.Instance))
{
fields.Add(prop.Name, prop.GetValue(p).ToString());
}
///etc....
And if you need the tag check to be case insensitive, you can use this instead of String.Replace():
string searchFor = #"\<\!" + key + #"\!\>";
text = Regex.Replace(text, searchFor, fields[key], RegexOptions.IgnoreCase);
I think you're looking for this:
var str = string.Format("Hello my name is {0} and I am {1} years old", name, age);
Or, since C# 6, you can just use this:
var str = $"Hello my name is {name} and I am {age} years old";

Getting Data From IEnumerable

I have text file which contains airport Codes in this format:
"AAA","","Anaa Arpt","PF","","","AAA","2","N","272"
I used a StreamReader to to read the line from file and then I add that line to string list finally I convert that list to IEnumerable type.
Can you please help me how could I get only three values from each line for example
AAA is airportCode
Anna Arpt airport name
PF is country Code
I want to get only these three values from each row.
Please find below the code.
using (StreamReader sr = new StreamReader("C:/AirCodes/RAPT.TXT"))
{
String line;
while ((line = sr.ReadLine()) != null)
{
aircodesFromTravelPort.Add(line);
Console.WriteLine(line);
}
}
var codes = (IEnumerable<String>)aircodesFromTravelPort;
foreach (var aircode in codes)
It seems that you can try using Linq, something like that:
var codes = File
.ReadLines(#"C:/AirCodes/RAPT.TXT")
.Select(line => line.Split(','))
.Select(items => new {
// I've created a simple anonymous class,
// you'd probably want to create you own one
Code = items[0].Trim('"'), //TODO: Check numbers
Airport = items[2].Trim('"'),
Country = items[3].Trim('"')
})
.ToList();
...
foreach(var item in codes)
Console.WriteLine(item);
You'll probably want to make use of String's Split function on each line to get the values into an array.
while ((line = sr.ReadLine()) != null)
{
var values = line.Split(","); // here you have an array of strings containing the values between commas
var airportCode = values[0];
var airportName = values[2];
var airportCountry = values[3];
var airportInfo = airportCode + "," + airportName + "," + airportCountry;
aircodesFromTravelPort.Add(airportInfo );
// what you actually do with the values is up to you, I just tried to make it as close to the original as possible.
Console.WriteLine(airportInfo);
}
Hope this helps!
I like Regex with named groups:
var line = #"""AAA"","""",""Anaa Arpt"",""PF"","""","""",""AAA"",""2"",""N"",""272""";
var pattern = #"^""(?<airportCode>\w+)"",""(\w*)"",""(?<ariportName>[\w\s]+)"",""(?<cuntryCode>\w+)""";
Match match = Regex.Match(line, pattern, RegexOptions.IgnoreCase);
if (match.Success)
{
string airportCode = match.Groups["airportCode"].Value;
string ariportName = match.Groups["ariportName"].Value;
string cuntryCode = match.Groups["cuntryCode"].Value;
}

Change CSV file column name

I have a CSV file which contains four columns i.e Name, Surname, Age, Data of Birth
I want to change the column Name to FullName. How can this be done in c# please?
var reader = new StreamReader(File.OpenRead(#"C:\myCSV.csv"));
var line = reader.ReadLine();
var values = line.Split(';');
var title = line.Split(',');
Console.WriteLine(title[0]);
if (title.Contains("Name"))
{
title[0] = "FullName";
}
Now I'm stuck on how should I continue to change the Column name
If you are attempting to create a new file with 3 columns instead of 4 this would be a starting point, however, you should use a csv parser. This is just a demonstration to show you how to combine the two columns.
string[] lines = System.IO.File.ReadAllLines(#"C:\myCSV.csv");
using (System.IO.StreamWriter file = new System.IO.StreamWriter(#"C:\myCSV2.csv"))
{
foreach (string line in lines)
{
if (line==lines[0])
{ //Change Header
file.WriteLine("Fullname,Age,Date of Birth");
}
else
{
string[] values = line.Split(',');
file.WriteLine(string.Format("{0} {1},{2},{3}",
values[0],values[1],values[2],values[3]));
}
}
}

StreamReader case sensitive

My program currently reads a text file and compares it with the value in a text box and then tells me how many matches, this currently works.
My query is that it is case sensitive. Is there any way to make it so it doesn't matter whether it is in upper or lower case?
This is my code below:
if (!String.IsNullOrEmpty(CustodianEAddress.Text))
{
for (AddressLength1 = 0; AddressLength1 < Length; AddressLength1++)
{
List<string> list1 = new List<string>();
using (StreamReader reader = new StreamReader(FileLocation))
{
string line1;
//max 500
string[] LineArray1 = new string[500];
while ((line1 = reader.ReadLine()) != null)
{
list1.Add(line1); // Add to list.
if (line1.IndexOf(cust1[AddressLength1].ToString()) != -1)
{
count1++;
LineArray1[count1] = line1;
}
}
reader.Close();
using (System.IO.StreamWriter filed =
new System.IO.StreamWriter(FileLocation, true))
{
filed.WriteLine("");
filed.WriteLine("The email address " +
cust1[AddressLength1].ToString() + " was found " + count1 +
" times within the recipient's inbox");
}
string count1a;
count1a = count1.ToString();
}
}
}
else
{
MessageBox.Show("Please Enter an Email Address");
}
So basically, I need to compare the value in cust1[AddressLength1] with any values found in an array which is in the text file.
String.Compare() takes in an optional parameter that let's you specify whether or not the equality check should be case sensitive.
Edited in response to code being posted
Compare and Index of both take in an optional enumeration, StringComparison. If you choose StringComparison.OrdinalIgnoreCase then case will be ignored.
Here's a quick way to compare two strings without checking case:
string a;
string b;
string.Compare(a, b, true);
The true here is passed as the value of the ignoreCase parameter, meaning that upper and lower-case letters will be compared as if they were all the same case.
EDIT:
I've cleaned up your code a bit, and also put in the compare function. I included comments where I changed stuff:
// Not needed: see below. List<string> list1 = new List<string>();
using (StreamReader reader = new StreamReader(FileLocation))
{
string line1;
//max 500
List<string> LineArray1 = new List<string>();
while ((line1 = reader.ReadLine()) != null)
{
// list1.Add(line1); // Add to list.
// By adding to the list, then searching it, you are searching the whole list for every single new line - you're searching through the same elements multiple times.
if (string.Compare(line1, cust1[AddressLength1].ToString(), true) == 0)
{
// You can just use LineArray1.Count for this instead. count1++;
LineArray1.Add(line1);
}
}
// Not needed: using() takes care of this. reader.Close();
using (System.IO.StreamWriter filed =
new System.IO.StreamWriter(FileLocation, true))
{
filed.WriteLine(); // You don't need an empty string for a newline.
filed.WriteLine("The email address " +
cust1[AddressLength1].ToString() + " was found " + LineArray1.Count +
" times within the recipient's inbox");
}
string count1a;
count1a = LineArray1.Count.ToString();
}
The fact you are reading from a file or not it does not matter, when compare
use the static string Comapare function:
public static int Compare(
string strA,
string strB,
bool ignoreCase
)
and pass true as a last parameter.

Extracting text from a file where date -time is the index

I have got around 800 files of maximum 55KB-100KB each where the data is in this format
Date,Time,Float1,Float2,Float3,Float4,Integer
Date is in DD/MM/YYYY format and Time is in the format of HH:MM
Here the date ranges from say 1st May to 1June and each day, the Time varies from 09:00 to 15:30.
I want to run a program so that, for each file, it extracts the data pertaining to a particular given date and writes to a file.
I am trying to get around, to form a to do a search and extract operation. I dont know, how to do it, would like to have some idea.
I have written the code below:
static void Main(string[] args)
{
string destpath = Directory.GetCurrentDirectory();
destpath += "\\DIR";
DirectoryInfo Dest = Directory.CreateDirectory(destpath);
DirectoryInfo Source = new DirectoryInfo(Directory.GetCurrentDirectory() + "\\IEOD");
FileInfo[] fiArr = Source.GetFiles("*.csv");
Console.WriteLine("Search Date:");
string srchdate = Console.ReadLine();
String FileNewLine;
String FileNewdt;
FileInfo r;
foreach (FileInfo f in fiArr)
{
r = new FileInfo(destpath + "\\" + f.Name);
r.Create();
StreamWriter Sw = r.AppendText();
StreamReader Sr = new StreamReader(f.FullName);
while (Sr.Peek() >= 0)
{
FileNewLine = Sr.ReadLine();
FileNewdt = FileNewLine.Substring(0,10);
if (String.Compare(FileNewdt, srchdate, true) == 0)
{
//write it to a file;
Console.WriteLine(FileNewLine);
}
}
}
Console.ReadKey();
}
As of now, it should write into the Console. The writing with the help of StreamWriter will be done later, but I am facing a runtime error. It says, " 'C:\Documents and Settings\Soham Das\Desktop\Test\DIR\ABAN.csv' because it is being used by another process."
Here ABAN is a newly created file, by the code. The problem is faced at StreamWriter Sw = r.AppendText()
Help appreciated.
Thanks
Soham
Now that you have edited the question to show that the delimiter is actually a comma instead of a slash (which would have conflicted with the date format) this becomes a lot easier. I've re-posted the answer from last night below.
// This would come from Stream.ReadLine() or something
string line = "02/06/2010,10:05,1.0,2.0,3.0,4.0,5";
string[] parts = line.Split(',');
DateTime date = DateTime.ParseExact(parts[0], "dd/MM/yyyy", null);
TimeSpan time = TimeSpan.Parse(parts[1]);
date = date.Add(time); // adds the time to the date
float float1 = Single.Parse(parts[2]);
float float2 = Single.Parse(parts[3]);
float float3 = Single.Parse(parts[4]);
float float4 = Single.Parse(parts[5]);
int integer = Int32.Parse(parts[6]);
Console.WriteLine("Date: {0:d}", date);
Console.WriteLine("Time: {0:t}", date);
Console.WriteLine("Float1: {0}", float1);
Console.WriteLine("Float2: {0}", float2);
Console.WriteLine("Float3: {0}", float3);
Console.WriteLine("Float4: {0}", float4);
Console.WriteLine("Integer: {0}", integer);
Obviously you can make it more resilient by adding error handling, using TryParse, etc. But this should give you a basic idea of how to manipulate strings in .NET.
So 800 files with around 100KB sums up to 80 KBytes. So why don't built up a little class like
public class Entry
{
public DateTime Date {get; set;}
public float Float1 {get; set;}
public int Integer1 {get; set;}
public Entry(string values)
{
//ToDo: Parse single line into properties
// e.g. use String.Split, RegEx, etc.
}
}
Also you should take care about implementing GetHashCode() and Equals() (there is a good explanation in the book Essential C#). And you should add the interface IComparable to that class which just makes somethine like
public int CompareTo(Entry rhs)
{
return this.Date.CompareTo(rhs.Date);
}
If you got this you can easily do the following:
var allEntries = new SortedList<Entry>();
string currentLine = null;
using (var streamReader = new StreamReader("C:\\MyFile.txt"))
while ((currentLine = streamReader.ReadLine()) != null)
{
try
{
var entry = new Entry(currentLine);
allEntries.Add(entry);
}
catch (Exception ex)
{
//Do whatever you like
//maybe just
continue;
//or
throw;
}
}
So what's missing is to read in all the files (instead of a single one). But this can be done by another loop on Directory.GetFiles() which maybe itself is looped through a Directory.GetDirectories().
After reading all the files into your List you can do whatever LINQ query comes to your mind.

Categories