StringReader finding all instances of my search - c#

I have a column (nvarchar(max)) in my table that contains javascript code. As you can see in my example I have 2 separate javascript calls per line.
Line 1:
(aaa)<LI> bbb
Line 2:
(ccc)<LI> ddd
I have the following StringReader code that is looping through the string, but it only finds the 1st instance. This code works great if there is only one instance of what I'm searching for per line.
using (StringReader rowData = new StringReader(reader[0].ToString()))
{
string line;
while ((line = rowData.ReadLine()) != null)
{
startVal = 0;
if (line.IndexOf("Javascript:TermDef", startVal) > -1)
{
startVal = line.IndexOf("Javascript:TermDef", startVal);
endVal = line.IndexOf(">", startVal);
value = line.Substring(startVal, endVal - startVal - 1);
Console.WriteLine(value);
}
}
}
How can I get it to find all instances of "JavaScript:TermDef" in my line?

Finding multiple instances is why the start argument exists. If you update your start value and loop through until no more instances are found, you can find all of them.
using (StringReader rowData = new StringReader(reader[0].ToString()))
{
string line;
while ((line = rowData.ReadLine()) != null)
{
startVal = 0;
while (line.IndexOf("Javascript:TermDef", startVal) > -1)
{
startVal = line.IndexOf("Javascript:TermDef", startVal);
endVal = line.IndexOf(">", startVal);
value = line.Substring(startVal, endVal - startVal - 1);
Console.WriteLine(value);
startVal = endVal;
}
}
}

Related

Reading data from a text file into a struct with different data types c#

I have a text file that stores data about cars, its call car.txt. I want to read this text file and categorize each of the sections for each car. Ultimately I want to add this information into a doubly linked list. So far everything I have tried is either giving me format exception or out of range exception.
This is my public structure
public struct cars
{
public int id;
public string Make;
public string Model;
public double Year;
public double Mileage;
public double Price;
}
This is where I try reading the data into the struct then add it to the DLL
static void Main()
{
int Key;
cars item = new cars();
int preKey;
/* create an empty double linked list */
DoubleLinkedList DLL = new DoubleLinkedList();
string line;
StreamReader file = new StreamReader(#"C:\Users\Esther\Desktop\cars.txt");
while ((line = file.ReadLine()) != null)
{
Console.WriteLine(line);
var array = line.Split(new string[] { "\r\n", "\n" }, StringSplitOptions.None);
item.Make =array[0];
item.Model = array[1];
item.Year = Double.Parse(array[2]);
item.Mileage = Double.Parse(array[2]);
item.Price = Double.Parse(array[2]);
// Using newline to seprate each line of the file.
Console.WriteLine(line);
DLL.AppendToHead(item);
}
This is throws a format exception then an out of range exception. How do I get this code to read the text file into the struct and add it to my DLL? This is the car.txt file
BMW
228i
2008
122510
7800
Honda
Accord
2011
93200
9850
Toyota
Camry
2010
85300
9500
I've changed your double-linked list to a plain List<cars> for simplicity. You need to create a new cars item for each record, otherwise you'll end up with every element in your list referring to the same record (the last one processed). Each line has a different attribute of the car so you need to work out which attribute to save, using a counter (idx).
using System.Collections.Generic; // for List<cars>
... ... ...
public static void ReadMultiline()
{
// http://stackoverflow.com/questions/39945520/reading-data-from-a-text-file-into-a-struct-with-different-data-types-c-sharp
var DLL = new List<cars>();
string line;
StreamReader file = new StreamReader(#"cars.txt");
var item = new cars();
int idx = 0;
while ((line = file.ReadLine()) != null)
{
idx++;
switch ( idx ) {
case 1: item.Make = line; break;
case 2: item.Model = line; break;
case 3: item.Year = Double.Parse(line); break;
case 4: item.Mileage = Double.Parse(line); break;
case 5: item.Price = Double.Parse(line); break;
}
if (line == "" && idx > 0 )
{
DLL.Add(item);
idx = 0;
item = new cars(); // create new cars item
}
}
// pick up the last one if not saved
if (idx > 0 )
DLL.Add(item);
foreach( var x in DLL )
{
Console.WriteLine( String.Format( "Make={0} Model={1} Year={2} Mileage={3} Price={4}", x.Make, x.Model, x.Year, x.Mileage, x.Price) );
}
}
You are reading the file line by line with ReadLine, and trying to split a single line with a line ending. This will result in an array with just one element (E.G. "BMW")
You can either read the whole file and then split by lines or just assume that each line will contain some data.
The OutOfRangeException refers to your invocation of array[1] when the array contains only array[0] = "BMW".

Text file to two string arrays in wpf using streamreader

I'm trying to read a text file to two string arrays. Array1 is to be all the odd lines, array2 all the even lines. I then add all the items of array1 to a combobox and when that is selected, or as it gets typed, outputs array2 to a textbox.
So far, I have tried a few methods from here, but the big issue seems to be creating the arrays. I tried to get help here before, but the answers didn't actually answer my question. They must be arrays, not lists (which I tried and worked well). I am really confused by this whole thing and my attempted code is now rubbish:
private void ReadFile(string filePath, string customerPhone, string customerName)
{
string line = string.Empty;
var fileSR = new StreamReader(filePath);
bool number = true;
while((line = fileSR.ReadLine()) != null)
{
if (number)
{
customerPhone(line);
number = false;
}
else
{
customerName(line);
number = true;
}
}
fileSR.Close();
}
I'm losing confidence in this whole process, but I need to find a way to make it work, then I can learn why it does.
You are almost there, just use the List<string>.
private void ReadFile(string filePath, string customerPhone, string customerName)
{
string line = string.Empty;
using (var fileSR = new StreamReader(filePath))
{
bool number = true;
List<string> customerPhone = new List<string>();
List<string> customerName = new List<string>();
while((line = fileSR.ReadLine()) != null)
{
if (number)
{
customerPhone.Add(line);
number = false;
}
else
{
customerName.Add(line);
number = true;
}
}
fileSR.Close();
}
}
If you are interested only in Arrays, you could simply call customerName.ToArray() to convert it to an array.
Linq Solution
Alternatively you could use Linq and do this.
var bothArrays = File.ReadLines("filepath") // Read All lines
.Select((line,index) => new {line, index+1}) // index each line
.GroupBy(x=> x/2) // Convert into two groups
.SelectMany(x=> x.Select(s=>s.line).ToArray()) // Convert it to array
.ToArray();
You should use collections to return data, say IList<String>:
private static void ReadFile(String filePath,
IList<String> oddLines,
IList<String> evenLines) {
oddLines.Clear();
evenLines.Clear();
int index = 1; //TODO: start with 0 or with 1
foreach (String line in File.ReadLines(filePath)) {
if (index % 2 == 0)
evenLines.Add(line);
else
oddLines.Add(line);
index += 1;
}
}
using
List<String> names = new List<String>();
List<String> phones = new List<String>();
ReadFile(#"C:\MyDate.txt", names, phones);
// If you want array representation
String[] myNames = names.ToArray();
String[] myPhones = phones.ToArray();
// Let's print out names
Console.Write(String.Join(Envrironment.NewLine, names));
Please, notice, that using File.ReadLines usually more convenient than StreamReader which should be wrapped in using:
// foreach (String line in File.ReadLines(filePath)) equals to
using (var fileSR = new StreamReader(filePath)) {
while ((line = fileSR.ReadLine()) != null) {
...
}
}
This worked! I have these class level strings:
string cFileName = "customer.txt";
string[] cName = new string[0];
string[] cPhone = new string[0];
And then this in the Window Loaded event, but could be used in it's own method:
private void Window_Loaded_1(object sender, RoutedEventArgs e)
{
//read file on start
int counter = 0;
string line;
StreamReader custSR = new StreamReader(cFileName);
line = custSR.ReadLine();
while (custSR.Peek() != -1)
{
Array.Resize(ref cPhone, cPhone.Length + 1);
cPhone[cPhone.Length - 1] = line;
counter++;
line = custSR.ReadLine();
Array.Resize(ref cName, cName.Length + 1);
cName[cName.Length - 1] = line;
counter++;
line = custSR.ReadLine();
phoneComboBox.Items.Add(cPhone[cPhone.Length - 1]);
}
custSR.Close();
//focus when program starts
phoneComboBox.Focus();
}

How to read multilines from text file in c#

I have a text file which contains user records.In the text file one user record is present in three lines of text file.Now as per my requirement i have to read first three lines for one User, Process it and insert into database and next three lines for second user and so on..
Here is the code that i have used for single line reading from text files..
if (System.IO.File.Exists(location) == true)
{
using (StreamReader reader = new StreamReader(location))
{
while ((line = reader.ReadLine()) != null)
{
line = line.Trim();
}
}
}
Please help me to read multi-lines , in this case 3 lines from text file ..
Thanks..
You could do something like:
if (System.IO.File.Exists(location) == true)
{
var lines=File.ReadAllLines(location);
int usersNumber = lines.Count() / 3;
for(int i=0; i < usersNumber; i++){
var firstField=lines[i*3];
var secondField=lines[i*3 +1];
var thirdField=lines[i*3 +2];
DoStuffs(firstField,secondField,thirdField);
}
if(lines.Count() > usersNumber *3) //In case there'd be spare lines left
DoSomethingElseFrom(lines, index=(usersNumber*3 +1));
}
You're reading all the lines of your file, counting how many users you have (group of 3), then for each group you're retrieving its associate info, and in the end you're processing the group of 3 fields related to the same user.
I have used a dummy dource file with this content:
line1_1 /*First line*/
line1_2
line1_3
line2_1 /*second line*/
line2_2
line2_3
line3_1 /*third line*/
line3_2
line3_3
line4_1 /*fourth line*/
line4_2
line4_3
string result = String.Empty;
string location = #"c:\users\asdsad\desktop\lines.txt";
if (System.IO.File.Exists(location) == true)
{
using (StreamReader reader = new StreamReader(location))
{
string line = String.Empty;
while ((line = reader.ReadLine()) != null) /*line has the first line in it*/
{
for(int i = 0; i<2; i++) /*only iterate to 2 because we need only the next 2 lines*/
line += reader.ReadLine(); /*use StringBuilder if you like*/
result += line;
}
}
result.Dump(); /*LinqPad Only*/
void Main()
{
var location = #"D:\text.txt";
if (System.IO.File.Exists(location) == true)
{
using (StreamReader reader = new StreamReader(location))
{
const int linesToRead = 3;
while(!reader.EndOfStream)
{
string[] currReadLines = new string[linesToRead];
for (var i = 0; i < linesToRead; i++)
{
var currLine = reader.ReadLine();
if (currLine == null)
break;
currReadLines[i] = currLine;
}
//Do your work with the three lines here
//Note; Partial records will be persisted
//var userName = currReadLines[0] ... etc...
}
}
}
}

Clearing a line of a txt file by the line ID

I have looked all over for the answer to this, but I can't find it anywhere. I need to be able to clear a line from a txt file by the last integer in the line (the ID number), but I have no idea how to do that. Please help? Basically I was thinking that I need to find the last integer, and if it does not equal to the input, then it would move to the next line until it finds the right integer. Then that line is cleared. Here is some of my code that obviously doesn't work:
public static void TicID(CommandArgs args)
{
if (args.Parameters.Count == 1)
{
if (i == 1)
{
try
{
string idToDelete = args.Parameters[0];
StreamReader idreader = new StreamReader("Tickets.txt");
StreamWriter iddeleter = new StreamWriter("Tickets.txt");
string id = Convert.ToString(idreader.Read());
string line = null;
while (idreader.Peek() >= 0)
{
if (String.Compare(id, idToDelete) == 0)
{
iddeleter.WriteLine(line);
}
else
{
idreader.ReadLine();
}
}
}
The most straightforward way to delete lines is to write the lines that should not be deleted:
var idToDelete = "1";
var path = #"C:\Temp\Test.txt";
var lines = File.ReadAllLines(path);
using (var writer = new StreamWriter(path, false)) {
for (var i = 0; i < lines.Length; i++) {
var line = lines[i];
//assuming it's a CSV file
var cols = line.Split(',');
var id = cols[cols.Length - 1];
if (id != idToDelete) {
writer.WriteLine(line);
}
}
}
This is the LINQ-way:
var lines = from line in File.ReadAllLines(path)
let cols = line.Split(',')
let id = cols[cols.Length - 1]
where id != idToDelete
select line;
File.WriteAllLines(path, lines);
Create a StreamReader object and read line by line into a string array or something like that using StreamReader's instance method ReadLine() and now find your line of choice in your text array and delete it.
Important note:
do { /*see description above*/ } while (streamReader.Peak() != -1);

Manipulating lines of data

I have millions of lines generated from data updated every second which look like this:
104500 4783
104501 8930
104502 21794
104503 21927
104505 5746
104506 9968
104509 5867
104510 46353
104511 7767
104512 4903
The column on the left represents time (hhmmss format), and the column on the right is data which is updated second-by-second. As you can see however, it isn't actually second-by-second, and there are some missing times (10:45:04, 10:45:07, 10:45:08 are missing in this example). My goal is to add in the missing seconds, and to use the data from the previous second for that missing second, like this:
104500 4783
104501 8930
104502 21794
104503 21927
104504 21927 --
104505 5746
104506 9968
104507 9968 --
104508 9968 --
104509 5867
104510 46353
104511 7767
104512 4903
I don't want the "--" in the result, I just put those there to mark the added lines. So far I've tried to accomplish this using StreamReader and StreamWriter, but it doesn't seem like they're going to get me what I want. I'm a newbie programmer and a newbie to C#, so if you could just point me in the right direction, that would be great. I'm really just wondering if this is even possible to do in C#...I've spent a lot of time on MSDN and here on SO looking for a solution to this, but so far haven't found any.
Edit: The lines are in a text file, and I want to store the newly created data in a new text file.
There are a few things you need to put together.
Read a file line-by-line: See here: Reading a Text File One Line at a Time
Writing a file line-by-line : StreamWriter.WriteLine
Keep track of the last read line. (Just use a variable in your while loop where you read the lines)
Check whether there is a gap. Maybe by parsing the first column (string.Split) using TimeSpan.Parse. If there is a gap then write the last read line, incrementing the timespan.
ok, here is the whole shooting match, tested and working against your test data:
public void InjectMissingData()
{
DataLine lastDataLine = null;
using (var writer = new StreamWriter(File.Create("c:\\temp\\out.txt")))
{
using (var reader = new StreamReader("c:\\temp\\in.txt"))
{
while (!reader.EndOfStream)
{
var dataLine = DataLine.Parse(reader.ReadLine());
while (lastDataLine != null && dataLine.Occurence - lastDataLine.Occurence > TimeSpan.FromSeconds(1))
{
lastDataLine = new DataLine(lastDataLine.Occurence + TimeSpan.FromSeconds(1), lastDataLine.Data);
writer.WriteLine(lastDataLine.Line);
}
writer.WriteLine(dataLine.Line);
lastDataLine = dataLine;
}
}
}
}
public class DataLine
{
public static DataLine Parse(string line)
{
var timeString = string.Format("{0}:{1}:{2}", line.Substring(0, 2), line.Substring(2, 2),
line.Substring(4, 2));
return new DataLine(TimeSpan.Parse(timeString), long.Parse(line.Substring(7, line.Length - 7).Trim()));
}
public DataLine(TimeSpan occurence, long data)
{
Occurence = occurence;
Data = data;
}
public TimeSpan Occurence { get; private set; }
public long Data { get; private set; }
public string Line
{
get { return string.Format("{0}{1}{2} {3}",
Occurence.Hours.ToString().PadLeft(2, Char.Parse("0")),
Occurence.Minutes.ToString().PadLeft(2, Char.Parse("0")),
Occurence.Seconds.ToString().PadLeft(2, Char.Parse("0")),
Data); }
}
}
In adition to all answers, considering that you are talking about a huge files, consider use of MemoryMappedFiles, can read here to see how to use them from C#.
This is not performance improvement, but memory improvement definetely is.
So far as inserting new entries between certain ones goes, I would advise reading in the text file into separated lines, and then storing them in a List. That way, you can use the Insert(...) method to insert your new lines. From there, you can write the lines back into the file.
When reading the lines, you can use either of the static helper methods in the System.IO.File class: ReadAllText and ReadAllLines.
Note: I've added links to the MSDN Documentation for each of the methods and classes I've mentioned, since you said you are new to C# and programming in general.
String prevTime;
String prevData;
while(String line = myStreamReader.ReadLine())
{
String[] parts = line.Split(new Char[] { ' ' });
String time = parts[0];
String data = parts[1];
Int32 iPrevTime = Int32.Parse(prevTime);
Int32 iCurrentTime = Int32.Parse(time);
// May need to loop here if you're missing more than one second
if(iCurrentTime > iPrevTime + 1)
AddData((iPrevTime + 1).ToString(), prevData);
AddData(time, data);
prevTime = time;
prevData = data;
}
Here is some pseudo-code to get you started. I think you will want this type of algorithm.
Here's some rough code for you. I'm not properly disposing everything, it's just to get you started.
DateTime lastTime;
string lastValue = null;
StreamReader reader = File.OpenText("path");
StreamWriter writer = new StreamWriter(File.OpenWrite("newPath"));
while (!reader.EndOfStream)
{
string[] lineData = reader.ReadLine().Split(' ');
DateTime currentTime = DateTime.Parse(lineData[0]);
string value = lineData[1];
if (lastValue != null)
{
while (lastTime < currentTime.AddSeconds(-1))
{
lastTime = lastTime.AddSeconds(1);
writer.WriteLine("{0} {1}", lastTime, lastValue);
}
}
writer.WriteLine("{0} {1}", currentTime, value);
lastTime = currentTime;
lastValue = value;
}
This assumes the times are never more than a second apart. If that assumption is wrong, it's easy enough to modify the below so it writes the lastValue in a loop for each second missing.
Update I missed in your example that it can in fact miss multiple seconds. I changed the example below to address that.
using (StreamReader reader = OpenYourInputFile())
using (StreamWriter writer = OpenYourOutputFile())
{
TimeSpan? lastTime;
TimeSpan currentTime, maxDiff = TimeSpan.FromSeconds(1);
string lastValue, currentline, currentValue, format = "{0:hhmmss} {1}";
while( (currentLine = reader.ReadLine()) != null)
{
string[] s = currentLine.Split(' ');
currentTime = DateTime.ParseExact("hhmmss", s[0] CultureInfo.InvariantCulture).TimeOfDay;
currentValue = s[1];
if (lastTime.HasValue && currentTime - lastTime.Value > maxDiff)
{
for(int x = 1; x <= (currentTime - lastTime).Seconds; x++) writer.WriteLine(string.Format(format, DateTime.Today.Add(lastTime).AddSeconds(x), lastValue);
}
writer.WriteLine(string.Format(format, DateTime.Today.Add(currentTime), currentValue);
lastTime = currentTime;
lastValue = currentValue;
}
}
string line;//The line that is read.
string previousLine = "0 0";
int prevTime = 0;
//These "using"'s are so that the resources they use will be freed when the block ( i.e. {} ) is finished.
using (System.IO.StreamReader originalFile = new System.IO.StreamReader("c:\\users\\Me\\t.txt"))
using (System.IO.StreamWriter newFile = new System.IO.StreamWriter("c:\\users\\Me\\t2.txt"))
{
while ((line = originalFile.ReadLine()) != null)
{
//"Split" changes the words in "line" (- that are separated by a space) to an array.
//"Parse" takes the first in that array (by using "[0]") and changes it into an integer.
int time = int.Parse(line.Split(' ')[0]);
while (prevTime != 0 && time > ++prevTime) newFile.WriteLine(prevTime.ToString() + " " + previousLine.Split(' ')[1]);
previousLine = line;
prevTime = time;
newFile.WriteLine(line);
}
}

Categories