Moving in text file with C# - c#

I have a problem with C#.
I am writing code to search a text file until it finds a certain word, then the code should move three lines and read the fourth, then continue the search to find the certain word again.
Now I don't know how to navigate through the file (forward and backward) to the line I want.
Can anybody help?

You can do something like this:
var text = File.ReadAllLines("path"); //read all lines into an array
var foundFirstTime = false;
for (int i = 0; i < text.Length; i++)
{
//Find the word the first time
if(!foundFirstTime && text[i].Contains("word"))
{
//Skip 3 lines - and continue
i = Math.Min(i+3, text.Length-1);
foundFirstTime = true;
}
if(foundFirstTime && text[i].Contains("word"))
{
//Do whatever!
}
}

// read file
List<string> query = (from lines in File.ReadLines(this.Location.FullName, System.Text.Encoding.UTF8)
select lines).ToList<string>();
for (int i = 0; i < query.Count; i++)
{
if (query[i].Contains("TextYouWant"))
{
i = i + 3;
}
}

Your requirements state that you are searching for a specific word. If that is true and you are not instead looking for a specific string, then the checked answer on this is wrong. Instead you should use:
string[] lines = System.IO.File.ReadAllLines("File.txt");
int skip = 3;
string word = "foo";
string pattern = string.Format("\\b{0}\\b", word);
for (int i = 0; i < lines.Count(); i++)
{
var match = System.Text.RegularExpressions.Regex.IsMatch(lines[i], pattern);
System.Diagnostics.Debug.Print(string.Format("Line {0}: {1}", Array.IndexOf(lines, lines[i], i) + 1, match));
if (match) i += skip;
}
If you use the string.contains method and the word you are searching for is "man", while your text somewhere contains "mantle" and "manual", the string.contains method will return as true.

Related

C# doesn't recognize some symbols

I read strings from text file, and among the strings there is one: "15121 ♥☺020 000000/=n531☻".
I use .Contain() method to spot ♥☺☻ symbols in the string, but it doesn't recognize them. For ♥,☺,☻ I also tried \u2665, \u263a, \u263b (as arguments for .Contain()), but none of them were recognized.
Moreover, I copied the string (from console output window) and pasted it into my code to compare symbols one by one.
string s = "15121 ♥☺020 000000/=n531☻"; // the same with "15121 \u2665\u263a020 000000/=n531\u263b"
for (int j = 0; j < s.Length; j++)
{
Console.WriteLine($"{line[j]} == {s[j]}: {line[j].Equals(s[j])}");
}
This is what I got:
What may be wrong and how do I recognize those symbols?
UPDATE: The input file I read strings from is a usual text file, and the strings inside looks like these (txt opened in Notepad):
As you can see, there is THE string among the others.
I don't use any encoding when reading the txt, and to specify how I do read the file and what the line is, here is my code:
string[] lines = File.ReadAllLines(path + target_file_name);
var list = new List<string>(lines);
for (int i = 0; i < list.Count; i++)
{
string line = list[i];
if (line.Length > 21)
{
Console.WriteLine(line);
if (line.Contains("/=n")) //used just to catch THE string
{
var line_b = Encoding.Unicode.GetBytes(line);
Console.WriteLine($"{line_b} : line = {line}");
foreach (byte m in line_b)
{
Console.Write(m + " ");
}
string s = "AAXX 15121 ♥☺020 000000/=n531☻";
Console.WriteLine();
var s_b = Encoding.Unicode.GetBytes(s);
Console.WriteLine($"{s_b} : s = {s}");
foreach (byte n in s_b)
{
Console.Write(n + " ");
}
Console.WriteLine();
for (int j = 0; j < s.Length; j++)
{
Console.WriteLine($"{line[j]} == {s[j]}: {line[j].Equals(s[j])}");
}
}
Reading all the lines from txt and converting them to List is a must for me. Thus, the line is a string line from initial txt file.
I have dumped the bytes of the inout text string var b = Encoding.Unicode.GetBytes(line); and compare with my literal (#pm100), and here is the result. Not quite sure what it does give me:
I'm sorry, I'm not willing to publish my code, and I may not understand some of your suggestions for I'm not very proficient in C# (and coding in general). So I would appreciate any further help as it is, if possible.

Replace substring from the listbox (WindowsForms)

I have attached in my listbox ( lb1 ) a character to the previous item. The letter A is seperated by a comma. Is it even possible to replace the letter in this line
(A --> B)? How can this be solved? The result in the listbox( lb2 ) should look as shown below.
if (listBox1.Items.Cast<string>().Contains("someText"))
{
int a = listBox1.Items.IndexOf("someText");
listBox1.Items.RemoveAt(a);
listBox1.Items.Insert(a, "newText");
}
Here is a code snippet for your new problem mikee:
You need to iterate through the items of the list box, search for a match, and replace the detected matches:
string search = "A";
string replace = "B";
for(int i = 0; i < lb1.Items.Count; i++)
{
if(lb1.Items[i].ToString().EndsWith(search))
{
string item = lb1.Items[i].ToString().Replace(search, replace);
lb1.Items[i] = item;
}
}
Edit
Please note that, the preceding snippet will change all the A characters in the string with B not only the last one. So if you have a list item say JONATHAN, A, the preceding code will change it to JONBTHBN, B. To avoid that you could do:
Solution 1:
for (int i = 0; i < lb1.Items.Count; i++)
{
if (lb1.Items[i].ToString().EndsWith(search))
{
int indx = lb1.Items[i].ToString().LastIndexOf(search);
string item = lb1.Items[i].ToString().Substring(0, indx) + replace;
lb1.Items[i] = item;
}
}
Solution 2:
If all of your list items are comma separated strings like the image above, then you could do:
for (int i = 0; i < lb1.Items.Count; i++)
{
if (lb1.Items[i].ToString().EndsWith(search))
{
var arr = lb1.Items[i].ToString().Split(',');
arr[arr.Length - 1] = replace;
lb1.Items[i] = string.Join(", ", arr);
}
}
Sorry for any inconvenience mikee.
Good luck.

C# - Foreach two line in Text File

I am developing in C#.
I have a text file containing the following:
Sam
NYC
Mii
Peru
LEO
Argentina
I want to iterate through this file two line by two line, then print to the console the first line, second line (the Name and the Country) of each couple, so the output would be:
Sam, NYC
Mii, Peru
Here is what I have tried:
int linenum = 0;
foreach (string line in File.ReadLines("c:\\file.txt"))
{
string word = line;
string s = "";
string j = "";
linenum = linenum + 1;
if(linenum % 2 != 0) //impaire
{
s = line;
}
else
{
j = line;
}
Console.WriteLine((string.Concat(s, j));
}
But that's not working, I want to do:
int linenum = 0;
foreach( two lines in File.ReadLines("c:\\file.txt"))
{
linenum = linenum + 1;
//get the first line (linenum = 1) and store it in a string s
// then get the second line (linenum = 2) and store it in a string j
// then print the two strings together to the console like that
Console.WriteLine((string.Concat("S: " + s,"J: " j));
}
How can I do that ?
Use File.ReadAllLines to return an array of strings:
var lines = File.ReadAllLines(filePath);
for (int i = 0; i < lines.Length; i+=2)
{
var s = lines[i];
var j = lines[i+1];
Console.WriteLine($"S: {s} J: {s}");
}
You do your output with Console.WriteLine in every line, but you also should do that only for every second line. Furthermore, your variables s and j live inside the loop's scope, so they are recreated with every iteration and loose their prior value.
int i = 0; string prev = "";
foreach (string line in File.ReadLines("c:\\file.txt")) {
if (i++ % 2 == 0) prev = line;
else Console.WriteLine($"{prev}, {line}");
}
Another approach would be iterating the array you get from File.ReadAllLines with an for loop instead of foreach and increase the index by 2
var lines = File.ReadAllLines("c:\\file.txt");
//make sure, you have an even number of lines!
if (lines.Length% 2 == 0) for (int i = 0; i < lines.Length; i+=2) {
Console.WriteLine($"{lines[i]}, {lines[i+1]}");
}
You can write yourself a little helper method to return batches of lines.
This implementation handles files that are not a multiple of the batch size (2 in your case) by returning "" for the missing lines at the end of the file.
public static IEnumerable<string[]> BatchedLinesFromFile(string filename, int batchSize)
{
string[] result = Enumerable.Repeat("", batchSize).ToArray();
int count = 0;
foreach (var line in File.ReadLines(filename))
{
result[count++] = line;
if (count != batchSize)
continue;
yield return result;
count = 0;
result = Enumerable.Repeat("", batchSize).ToArray();
}
if (count > 0)
yield return result;
}
Note that this also returns a separate array for each result, in case you make a copy of it.
Given that code, you can use it like so:
foreach (var batch in BatchedLinesFromFile(filename, 2))
{
Console.WriteLine(string.Join(", ", batch));
}
Actually, you can use LINQ to get two lines in a time using Take
var twoLines = File.ReadLines(#"YourPath").Take(2));
As you can use Skip to skip the two lines you took and take the next two lines like :
var twoLines = File.ReadLines(#"YourPath").Skip(2).Take(2));
EDIT : Thanks for #derpirscher there were a performance issue so changed the code to the following :
first read the whole file and store it in a string array
then loop through it using LINQ to take two elements from the array in a time.
string[] myStringArray = File.ReadAllLines(#"YourFile.txt");
for (int i = 0; i < myStringArray.Length ; i+=2)
{
var twoLines = myStringArray.Skip(i).Take(2).ToArray();
}
Another one, using Enumerable.Repeat() and an interger selector incremented a [NumberOfLines / 2] times.
Could be interesting for the LINQ addicted (a for / foreach solution is probably better anyway).
string[] input = File.ReadAllLines([SourcePath]);
int Selector = -1;
string[] output = Enumerable.Repeat(0, input.Length / 2).Select(_ => {
Selector += 2;
return $"{input[Selector - 1]} {input[Selector]}";
}).ToArray();
The output is:
Sam NYC
Mii Peru
LEO Argentina
Use the right tool for the job. foreach() is not the right tool here.
Without giving up the memory efficiency of ReadLines() over ReadAll():
using (var lines = File.ReadLines("c:\\file.txt").GetEnumerator())
{
while (lines.MoveNext())
{
string firstLine = lines.Current;
if (!lines.MoveNext())
throw new InvalidOperationException("odd nr of lines");
string secondLine = lines.Current;
// use 2 lines
Console.WriteLine("S: " + firstLine ,"J: " + secondLine);
}
}

Split string after certain character count

I need some help. I'm writing an error log using text file with exception details. With that I want my stack trace details to be written like the below and not in straight line to avoid the user from scrolling the scroll bar of the note pad or let's say on the 100th character the strings will be written to the next line. I don't know how to achieve that. Thanks in advance.
SAMPLE(THIS IS MY CURRENT OUTPUT ALL IN STRAIGHT LINE)
STACKTRACE:
at stacktraceabcdefghijklmnopqrstuvwxyztacktraceabcdefghijklmnopqrswxyztacktraceabcdefghijk
**MY DESIRED OUTPUT (the string will write to the next line after certain character count)
STACKTRACE:
at stacktraceabcdefghijklmno
pqrstuvwxyztacktraceabcdefgh
ijklmnopqrswxyztacktraceabcd
efghijk
MY CODE
builder.Append(String.Format("STACKTRACE:"));
builder.AppendLine();
builder.Append(logDetails.StackTrace);
Following example splits 10 characters per line, you can change as you like {N} where N can be any number.
var input = "stacktraceabcdefghijklmnopqrstuvwxyztacktraceabcdefghijklmnopqrswxyztacktraceabcdefghijk";
var regex = new Regex(#".{10}");
string result = regex.Replace(input, "$&" + Environment.NewLine);
Console.WriteLine(result);
Here is the Demo
you can use the following code:
string yourstring;
StringBuilder sb = new StringBuilder();
for(int i=0;i<yourstring.length;++i){
if(i%100==0){
sb.AppendLine();
}
sb.Append(yourstring[i]);
}
you may create a function for this
string splitat(string line, int charcount)
{
string toren = "";
if (charcount>=line.Length)
{
return line;
}
int totalchars = line.Length;
int loopcnt = totalchars / charcount;
int appended = 0;
for (int i = 0; i < loopcnt; i++)
{
toren += line.Substring(appended, charcount) + Environment.NewLine;
appended += charcount;
int left = totalchars - appended;
if (left>0)
{
if (left>charcount)
{
continue;
}
else
{
toren += line.Substring(appended, left) + Environment.NewLine;
}
}
}
return toren;
}
Best , Easiest and Generic Answer :). Just set the value of splitAt to the that number of character count after that u want it to break.
string originalString = "1111222233334444";
List<string> test = new List<string>();
int splitAt = 4; // change 4 with the size of strings you want.
for (int i = 0; i < originalString.Length; i = i + splitAt)
{
if (originalString.Length - i >= splitAt)
test.Add(originalString.Substring(i, splitAt));
else
test.Add(originalString.Substring(i,((originalString.Length - i))));
}

How can I read X lines down from another line in a text file?

I have a text file that I load into a string array. The contents of the file looks something like this:
OTI*IA*IX*NA~ REF*G1*J EVERETTE~ REF*11*0113722462~
AMT*GW*229.8~ NM1*QC*1*JENNINGS*PHILLIP~ OTI*IA*IX*NA~ REF*G1*J
EVERETTE~ REF*11*0113722463~ AMT*GW*127.75~
NM1*QC*1*JENNINGS*PHILLIP~ OTI*IA*IX*NA~ REF*G1*J EVERETTE~
REF*11*0113722462~ AMT*GW*10.99~ NM1*QC*1*JENNINGS*PHILLIP~ ...
I'm looking for the lines that start with OTI, and if it's followed by "IA" then I need to get the 10 digit number from the line that starts with REF*11. So far, I have this:
string[] readText = File.ReadAllLines("myfile.txt");
foreach (string s in readText) //string contains 1 line of text from above example
{
string[] currentline = s.Split('*');
if (currentline[0] == "OTI")
{
//move down 2 lines and grab the 10 digit
//number from the line that starts with REF*11
}
}
The line I need is always 2 lines after the current OTI line. How do I access the line that's 2 lines down from my current line?
Instead of using foreach() you can use a for(int index = 0; index < readText.Length; index++)
Then you know the line you are accessing and you can easily say int otherIndex = index + 2
string[] readText = File.ReadAllLines("myfile.txt");
for(int index = 0; index < readText.Length; index++)
{
string[] currentline = readText[index].Split('*');
if (currentline[0] == "OTI")
{
//move down 2 lines and grab the 10 digit
//number from the line that starts with REF*11
int refIndex = index + 2;
string refLine = readText[refIndex];
}
}
What about:
string[] readText = File.ReadAllLines("myfile.txt");
for (int i = 0; i < readText.Length; i++)
{
if (readText[i].StartsWith("OTI") && readText[i+2].StartsWith("REF*11")){
string number = readText[i+2].Substring("REF*11".Length, 10);
//do something
}
}
This looks like an EDI file! Ahh, EDI, the memories...
The good news is that the EDI file is delimited, just like most CSV file formats. You can use any standard CSV file library to load the EDI file into a gigantic array, and then iterate through it by position.
I published my open source CSV library here, feel free to use it if it's helpful. You can simply specify the "asterisk" as the delimiter:
https://code.google.com/p/csharp-csv-reader/
// This code assumes the file is on disk, and the first row of the file
// has the names of the columns on it
DataTable dt = CSVReader.LoadDataTable(myfilename, '*', '\"');
At this point, you can iterate through the datatable as normal.
for (int i = 0; i < dt.Rows.Count; i++) {
if (dt.Rows[i][0] == "OTI") {
Console.WriteLine("The row I want is: " + dt.Rows[i + 2][0]);
}
}
If you want to use regex to tokenize the items and create dynamic entities, here is such a pattern
string data = #"NM1*QC*1*JENNINGS*PHILLIP~
OTI*IA*IX*NA~
REF*G1*J EVERETTE~
REF*11*0113722463~
AMT*GW*127.75~
NM1*QC*1*JENNINGS*PHILLIP~
OTI*IA*IX*NA~
REF*G1*J EVERETTE~
REF*11*0113722462~
AMT*GW*10.99~
NM1*QC*1*JENNINGS*PHILLIP~";
string pattern = #"^(?<Command>\w{3})((?:\*)(?<Value>[^~*]+))+";
var lines = Regex.Matches(data, pattern, RegexOptions.Multiline)
.OfType<Match>()
.Select (mt => new
{
Op = mt.Groups["Command"].Value,
Data = mt.Groups["Value"].Captures.OfType<Capture>().Select (c => c.Value)
}
);
That produces a list of items like this which you can apply your business logic to:
Why dont you use regular expression matches using Regex.Match or Regex.Matches defined in System.Text.RegularExpressions? You can also look at string pattern matching algorithms such as the Knuth-Morris-Pratt algorithms.
string[] readText = File.ReadAllLines("myfile.txt");
foreach (string s in readText) //string contains 1 line of text from above example
{
string[] currentline = s.Split('*');
if (currentline[0] == "REF"&&currentline[1] == "11")
{
found=false;
needed=current+2;
}
}
string[] readText = File.ReadAllLines("myfile.txt");
for(int linenum = 0;linenum < readText.Length; linenum++)
{
string s = readText[linenum];
string[] currentline = s.Split('*');
if (currentline[0] == "OTI")
{
//move down 2 lines and grab the 10 digit
linenum +=2;
string refLine = readText[linenum];
//number from the line that starts with REF*11
// Extract your number here from refline
}
}
Thank guys .. this is what I came up with, but I'm also reading your answers as I KNOW I will learn something! Thanks again!
string[] readText = File.ReadAllLines("myfile.txt");
int i = 0;
foreach (string s in readText)
{
string[] currentline = s.Split('*');
if (currentline[0] == "OTI")
{
lbRecon.Items.Add(readText[i+2].Substring(8, 9));
}
i++;
}

Categories

Resources