We have a sample text file with the text:
The things God has prepared for those who love him
We read the text into datatable and assigned some values like this:
The 1
----------
things 2
----------
God 3
----------
has 4
----------
prepared 5
----------
for 6
----------
those 7
----------
who 8
----------
love 9
----------
him 10
----------
We're trying to replace the text in the input file with these corresponding numbers.
Is it possible? If possible, how can we do it?
Edit2:
we edited our code like this:
:
void replace()
{
string s1, s2;
StreamReader streamReader;
streamReader = File.OpenText("C:\\text.txt");
StreamWriter streamWriter = File.CreateText("C:\\sample1.txt");
int x = st.Rows.Count;
int i1 = 0;
// Now, read the entire file into a string
while ((line = streamReader.ReadLine()) != null)
{
for (int i = 0; i < x; i++)
{
s1 = Convert.ToString(st.Rows[i]["Word"]);
s2 = Convert.ToString(st.Rows[i]["Binary"]);
s2+="000";
char[] delimiterChars = { ' ', '\t' };
string[] words = line.Split(delimiterChars);
// Write the modification into the same file
string ab = words[i1]; // exception occurs here
// Console.WriteLine(ab);
streamWriter.Write(ab.Replace(s1, s2));
i1++;
}
}
streamReader.Close();
streamWriter.Close();
}
but we're getting an "Array index out of bounds" exception. we're unable to find the problem.
thanks in advance
here is a bit of code to help you get going, it hasn't been extensively tested:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
File.WriteAllText("sample1.txt", "The things God has prepared for those who love him the");
string text = File.ReadAllText("sample1.txt").ToLower();
var words = text
.Split(new [] { ' ' }, StringSplitOptions.RemoveEmptyEntries)
.Distinct()
.OrderByDescending(word => word.Length);
var values = new Dictionary<string, int>();
for (int i = 0; i < words.Count(); i++)
{
values.Add(words.ElementAt(i), i + 1);
}
foreach (var kvp in values)
{
text = text.Replace(kvp.Key, kvp.Value.ToString());
}
File.WriteAllText("sample1.txt", text);
Console.WriteLine("Press ENTER to exit");
Console.ReadLine();
}
}
}
it creates a test text file, reads it, converts it to lowercase, makes identifiers for distinct words, and replaces text based on those identifiers. long words are replaced before short words to offer a bit of bad replacement prevention.
UPDATE: I just noticed the question was updated and it's no longer an option to read the entire file in one string.. sigh.. so my answer only applies when you read and write all text in one go, maybe you can reuse parts of it when reading and writing per word.
Related
Here the code that I create to replace some value at txt file.
I want to replace the value 0 with 3 for lines which do not start with "#".
using (StreamWriter sr = new StreamWriter(#"D:\Testing\Ticket_post_test.txt"))
foreach(string line in File.ReadLines(#"D:\Testing\Ticket_post.txt"))
{
string[] getFromLine = line.Split(' ');
if (getFromLine[0].Equals("#") == false)
{
if (getFromLine[10].Equals("0") == true) ;
(getFromLine[10]).Replace("0", "3");
}
sr.WriteLine(line);
}
Stuck at how to replace the 0 by 3 at line split[10] and write to a new txt file.
The txt file show below
*#* start time = 2021-12-03-15-14-55
*#* end time = 2021-12-03-15-15-41
*#* name = SYSTEM
bot 10 pad 11 d 4 e 6 t #0 **0** 2021-12-03-15-14-55 # - 2021-12-03-15-15-41
bot 11 pad 12 d 5 e 7 t #0 **0** 2021-12-03-15-14-55 # - 2021-12-03-15-15-41
bot 12 pad 13 d 6 e 8 t #0 **1** 2021-12-03-15-14-55 # - 2021-12-03-15-15-41
and more
Your code makes some erroneous assumptions, which I will correct here:
When you split a string using .Split or .Substring, you are not creating a little window/little windows into the original string. You are producing altogether new strings.
When you use .Replace, you are creating a new string with the altered values, not modifying the original in-place. See this question for more info on that.
This means that:
Your replace is a no-op (it does nothing of any meaning).
Your WriteLine is just writing the original line value back to the file without your changes.
We need to both fix your replace, and create the updated string to write to the file. As we are checking the value of getFromLine[10], we don't need .Replace at all, we can just set a new value:
using (StreamWriter sr = new StreamWriter(#"D:\Testing\Ticket_post_test.txt"))
{
foreach (string line in File.ReadLines(#"D:\Testing\Ticket_post.txt"))
{
string[] getFromLine = line.Split(' ');
if (getFromLine[0] != "#" && getFromLine[10] == "0")
{
getFromLine[10] = "3";
}
sr.WriteLine(String.Join(" ", getFromLine));
}
}
This isn't especially efficient, but it should get the job done. You could potentially modify it like this to avoid creating a new string when no changes have been made:
using (StreamWriter sr = new StreamWriter(#"D:\Testing\Ticket_post_test.txt"))
{
foreach (string line in File.ReadLines(#"D:\Testing\Ticket_post.txt"))
{
string[] getFromLine = line.Split(' ');
if (getFromLine[0] != "#" && getFromLine[10] == "0")
{
getFromLine[10] = "3";
sr.WriteLine(String.Join(" ", getFromLine));
}
else
{
sr.Write(line);
}
}
}
Note that you should probably also check the length of the array (i.e. if (getFromLine.Length >= 11 && getFromLine[0] != "#" && getFromLine[10] == "0") so that you don't get any IndexOutOfRangeException errors if you reach a line of the file that has less spaces than you expect (e.g. a blank line).
P.S. I've not tested this, so I've assumed that the rest of your logic is sound.
I think this simple example will suit to your working problem.
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
namespace Stack5
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow
{
public MainWindow()
{
InitializeComponent();
ReadAndWriteTextFile();
}
private static void ReadAndWriteTextFile()
{
// Read text file
// (?<string> ...) = name it with "string" name
// ^(?!#) = select line not begin with "#"
// (\S+\s){10} = bypass 10 group strings include a visible characters (\S) and a space (\s)
string pattern = #"(?<one>^(?!#)(\S+\s){10})0(?<two>.+)";
string substitution = #"${one}3${two}";
Regex regex = new Regex(pattern);
// Change the path to your path
List<string> lines = File.ReadLines(#".\settings.txt").ToList();
for (int i = 0; i < lines.Count(); i++)
{
// Check its value
Debug.WriteLine(lines[i]);
var match = Regex.Match(lines[i], pattern);
if (match.Success)
{
string r = regex.Replace(lines[i], substitution);
// Check its value
Debug.WriteLine("Change the line {0} to: {1}",i+1,r);
lines[i] = r;
}
}
// Write text file
File.WriteAllLines(#".\settings.txt",lines);
}
}
}
I tested it in my local machine, hope this helps you!
Ask me if you need, good to you good to me : D
I have .txt file with 10 954 lines in the format of 6,4:10
I need to load that .txt file with StreamReader and split every line at ':' into 2D array.
To look like this
[6,4 10]
[5,2 15]
[9,3 20]
So i can later on count each column and place it in a particular category.
This is the furthest i got so far
StreamReader ulaz = new StreamReader("C:\\Users\\Core\\Desktop\\podaciC.txt");
string[] polje = new string[10954];
while (!ulaz.EndOfStream)
{
for (int i = 0; i < polje.GetLength(0); i++)
{
polje[i] = ulaz.ReadLine();
}
}
ulaz.Close();
foreach (string s in polje)
{
Console.WriteLine(s);
}
Console.ReadKey();
Here is documentation for the ReadLine() method of the StreamReader: https://msdn.microsoft.com/da-dk/library/system.io.streamreader.readline(v=vs.110).aspx
Here is documentation for the Split() method of the String: https://msdn.microsoft.com/en-us/library/system.string.split(v=vs.110).aspx
You can solve this using those methods.
I would provide code, but that wouldn't be ethical since you haven't indicated that you've tried to solve this problem. I can help you solve your homework, but I won't solve it for you.
No need to fight with arrays and StreamReader. Easy to understand example:
using System.Collections.Generic;
using System.IO;
namespace ConsoleApplication2
{
class Program
{
static void Main (string[] args)
{
var filePath = "C:\\Users\\Core\\Desktop\\podaciC.txt";
var result = new List<KeyValuePair<decimal, int>> (11000); // create list with initial capacity
var lines = File.ReadLines (filePath); // allows to read file line by line (without loading entire file into memory)
foreach (var line in lines)
{
string[] splittedLine = line.Split (':'); // split line into array of two elements
decimal key = decimal.Parse (splittedLine[0]); // parse first element
int value = int.Parse (splittedLine[1]); // parse second element
var kvp = new KeyValuePair<decimal, int> (key, value); // create tuple
result.Add (kvp);
}
}
}
}
I suggest you to create custom class like LineParser or something which will handle errors for invalid lines etc.
My example file uses these strings in it one string on each line:
6,4:10
6,4:10
6,4:10
6,4:10
Use Linq to get all lines and split them based on :
Get all lines and every line will be represented by a string all lines make up one array of strings
then select these result and split the string by and : on every index of the string array (lines).
Convert the the IEnumerable of string[] to array
string[][] array = File.ReadAllLines("C:\\t\\My File2.txt")
.Select(x => x.Split(':'))
.ToArray();
Out putting values to the console:
int counter = 0;
foreach (var rows in array)
{
foreach (var number in rows)
{
Console.Write("Number row {0} = {1}\t", counter, number);
}
Console.WriteLine();
counter++;
}
How the array looks:
string[4][]
{
string[2] { [0] => 6,4 [1] => 10 }
string[2] { [0] => 6,4 [1] => 10 }
string[2] { [0] => 6,4 [1] => 10 }
string[2] { [0] => 6,4 [1] => 10 }
}
Console Output
Number row 0 = 6,4 Number row 0 = 10
Number row 1 = 6,4 Number row 1 = 10
Number row 2 = 6,4 Number row 2 = 10
Number row 3 = 6,4 Number row 3 = 10
I have a hard time figuring out how to remove extra letters using Regex.
I have this example below that says that it has 42 of "|" (vertical bars) per line.
|V.7|42|
1|0|1|58|4|4|351|25|8|||1|0||6|3|1000|49|20|430|17|6|0|10|0|1200|25||30|20|20|20|20|0|100|61028|1|0|0|1|1|0|
1|0|1|58|4|4|351|25|8|||1|0||6|3|1000|49|20|430|17|6|0|10|0|1200|25||30|20|20|20|20|0|100|61028|1|0|0|1|1|0|
2|543|2|58|4|4|366|26|9|100||2|200||8|3|1000|49|20|430|17|6|10|21|54|2400|36||30|20|20|20|20|543|150|61028|2|100|1|2|2|0|
3|1230|3|60|5|5|390|26|10|100||3|1500||10|3|1000|49|20|430|17|6|10|32|123|4800|46||30|20|20|20|20|1230|200|61028|3|1000|2|3|3|0|
4|2002|4|61|6|6|424|27|12|100||4|6000||12|4|769|37|15|315|12|4|10|45|200|9600|57||30|20|20|20|20|2002|250|61028|4|5000|3|4|4|0|
5|3306|5|63|7|7|468|29|14|100||5|18000||16|4|556|27|11|208|8|2|10|58|331||69||30|20|20|20|20|3306|300|61027|1|10000|4|5|5|0|
6|4950|6|66|8|8|522|31|17|100||6|||18|4|435|21|9|147|6|1|10|74|495||80||30|20|20|20|20|4950|350|61027|2|30000|5|6|6|0|
7|6947|7|69|10|10|585|33|20|100||7|||20|4|333|17|7|97|4|1|10|90|695||92||20|15|15|15|15|6947|400|61027|3|50000|6|7|7|0|
8|9309|8|73|12|12|658|35|24|100||8|||24|4|286|14|6|73|3|1|10|109|931||105||20|15|15|15|15|9309|450|61026|1|100000|7|8|8|0|
9|12050|9|77|14|14|741|38|28|100||9|||27|5|250|13|5|55|3|1|10|129|1205||117||20|15|15|15|15|12050|500|61026|2|300000|8|9|9|0|
10|15183|10|82|16|16|834|41|33|100|100|10|||29|5|222|11|4|0|0|0|10|151|1366||130|5|20|15|15|15|15|15183|550|61025|1|500000|9|10|10|0|
11|18720|11|87|19|19|936|45|38|100|100|11|||31|5|200|10|4|0|0|0|11|176|1685||143|10|20|15|15|15|15|18720|600|||||||0|
12|21335|12|92|22|22|1048|48|44|100|100|12|||36|5|182|9|4|0|0|0|12|203|2134||157|15|10|15|10|10|10|21335|650|||||||0|
Now I have another one with 45, what I want is to remove the new letters so that it has exactly 42 vertical bars like above.
|V.8|45|
1|0|1|58|4|4|351|25|8|||1|0||6|3|1000|49|20|430|17|6|0|10|0|1200|25||30|20|20|20|20|0|100|61028|1|0|0|1|1|0|5000|40022|1|
2|543|2|58|4|4|366|26|9|100||2|200||8|3|1000|49|20|430|17|6|10|21|54|2400|36||30|20|20|20|20|543|150|61028|2|100|1|2|2|0|25000|61034|1|
3|1230|3|60|5|5|390|26|10|100||3|1500||10|3|1000|49|20|430|17|6|10|32|123|4800|46||30|20|20|20|20|1230|200|61028|3|1000|2|3|3|0|75000|40250|1|
4|2002|4|61|6|6|424|27|12|100||4|6000||12|4|769|37|15|315|12|4|10|45|200|9600|57||30|20|20|20|20|2002|250|61028|4|5000|3|4|4|0|160000|61035|1|
5|3306|5|63|7|7|468|29|14|100||5|18000||16|4|556|27|11|208|8|2|10|58|331||69||30|20|20|20|20|3306|300|61027|1|10000|4|5|5|0|300000|40355|3|
6|4950|6|66|8|8|522|31|17|100||6|||18|4|435|21|9|147|6|1|10|74|495||80||30|20|20|20|20|4950|350|61027|2|30000|5|6|6|0||||
7|6947|7|69|10|10|585|33|20|100||7|||20|4|333|17|7|97|4|1|10|90|695||92||20|15|15|15|15|6947|400|61027|3|50000|6|7|7|0||||
8|9309|8|73|12|12|658|35|24|100||8|||24|4|286|14|6|73|3|1|10|109|931||105||20|15|15|15|15|9309|450|61026|1|100000|7|8|8|0||||
9|12050|9|77|14|14|741|38|28|100||9|||27|5|250|13|5|55|3|1|10|129|1205||117||20|15|15|15|15|12050|500|61026|2|300000|8|9|9|0||||
10|15183|10|82|16|16|834|41|33|100|100|10|||29|5|222|11|4|0|0|0|10|151|1366||130|5|20|15|15|15|15|15183|550|61025|1|500000|9|10|10|0||||
11|18720|11|87|19|19|936|45|38|100|100|11|||31|5|200|10|4|0|0|0|11|176|1685||143|10|20|15|15|15|15|18720|600|||||||0||||
12|21335|12|92|22|22|1048|48|44|100|100|12|||36|5|182|9|4|0|0|0|12|203|2134||157|15|10|15|10|10|10|21335|650|||||||0||||
And I have this code at the moment:
public string Fix(string FileName, int columnsCount)
{
var InputFile = File.ReadLines(FileName).Skip(1).ToArray();
string Result = "";
for(int i = 0; i < InputFile.Length; i++)
{
int FoundMatches = Regex.Matches(Regex.Escape(InputFile[i]), FindWhatTxtBox.Text).Count;
// If too many letters found, trim the rest.
if(FoundMatches > CountTxtBox.Text.Length)
{
string CurrentLine = InputFile[i];
}
}
return Result;
}
As you can see each line has either one to no numbers inside its vertical bar. How can I remove the extra letters?
Do you have to use a RegEx? It can also be done with string manipulation like this:
using System;
using System.Linq;
public class Program
{
public static void Main()
{
string s = "1|0|1|58|4|4|351|25|8|||1|0||6|3|1000|49|20|430|17|6|0|10|0|1200|25||30|20|20|20|20|0|100|61028|1|0|0|1|1|0|5000|40022|1|";
var arr = s.Split('|') ;
var retVal = String.Join("|", arr.Take(43));
Console.WriteLine(retVal);
}
}
It takes 43 because the 1st digit seems a counter to me... But you can make it 42 of course. Beware that this code will fail is there are less than 43 entries to work with.
Too simple to use Regex. See code below :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace ConsoleApplication1
{
class Program
{
const string INPUT_FILENAME = #"c:\temp\test.txt";
const string OUTPUT_FILENAME = #"c:\temp\test1.txt";
static void Main(string[] args)
{
StreamReader reader = new StreamReader(INPUT_FILENAME);
StreamWriter writer = new StreamWriter(OUTPUT_FILENAME);
string inputLine = "";
int lineCount = 0;
while ((inputLine = reader.ReadLine()) != null)
{
if (++lineCount == 1)
{
writer.WriteLine(inputLine);
}
else
{
string[] inputArray = inputLine.Split(new char[] {'|'});
writer.WriteLine(string.Join("|", inputArray.Take(43)));
}
}
reader.Close();
writer.Flush();
writer.Close();
}
}
}
Here is a data file, let us keep it easy by only needing 5 items but still using Regex.
Keep your examples small for StackOverflow...one will get more answers.
The below code can be changed to 42 ({0,42}) or any number as needed, but the example will read then write out only 5.
Data File
1|2|3|4|5|6|7|8|9|10
10|9|8|7|6|5|4|3|2|1|0|1|
||||||||||||11|12|
Code To get 0 to 5 Items per line
var data = File.ReadAllText(#"C:\Temp\test.txt");
string pattern = #"^(\d*\|){0,5}";
File.WriteAllLines(#"C:\Temp\testOut.txt",
Regex.Matches(data, pattern, RegexOptions.Multiline)
.OfType<Match>()
.Select(mt => mt.Groups[0].Value));
Resultant File
1|2|3|4|5|
10|9|8|7|6|
|||||
I've tried a few different methods and none of them work correctly so I'm just looking for someone to straight out show me how to do it . I want my application to read in a file based on an OpenFileDialog.
When the file is read in I want to go through it and and run this function which uses Linq to insert the data into my DB.
objSqlCommands.sqlCommandInsertorUpdate
However I want to go through the string , counting the number of ","'s found . when the number reaches four I want to only take the characters encountered until the next "," and do this until the end of the file .. can someone show me how to do this ?
Based on the answers given here my code now looks like this
string fileText = File.ReadAllText(ofd.FileName).Replace(Environment.NewLine, ",");
int counter = 0;
int idx = 0;
List<string> foo = new List<string>();
foreach (char c in fileText.ToArray())
{
idx++;
if (c == ',')
{
counter++;
}
if (counter == 4)
{
string x = fileText.Substring(idx);
foo.Add(fileText.Substring(idx, x.IndexOf(',')));
counter = 0;
}
}
foreach (string s in foo)
{
objSqlCommands.sqlCommandInsertorUpdate("INSERT", s);//laClient[0]);
}
However I am getting an "length cannot be less than 0" error on the foo.add function call , any ideas ?
A Somewhat hacky example. You would pass this the entire text from your file as a single string.
string str = "1,2,3,4,i am some text,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20";
int counter = 0;
int idx = 0;
List<string> foo = new List<string>();
foreach (char c in str.ToArray())
{
idx++;
if (c == ',')
{
counter++;
}
if (counter == 4)
{
string x = str.Substring(idx);
foo.Add(str.Substring(idx, x.IndexOf(',')));
counter = 0;
}
}
foreach(string s in foo)
{
Console.WriteLine(s);
}
Console.Read();
Prints:
i am some text
9
13
17
As Raidri indicates in his answer, String.Split is definitely your friend. To catch every fifth word, you could try something like this (not tested):
string fileText = File.ReadAllText(OpenDialog.FileName).Replace(Environment.NewLine, ",");
string words[] = fileText.Split(',');
List<string> everFifthWord = new List<string>();
for (int i = 4; i <= words.Length - 1, i + 5)
{
everyFifthWord.Add(words[i]);
}
The above code reads the selected file from the OpenFileDialog, then replaces every newline with a ",". Then it splits the string on ",", and starting with the fifth word takes every fifth word in the string and adds it to the list.
File.ReadAllText reads a text file to a string and Split turns that string into an array seperated at the commas:
File.ReadAllText(OpenDialog.FileName).Split(',')[4]
If you have more than one line use:
File.ReadAllLines(OpenDialog.FileName).Select(l => l.Split(',')[4])
This gives an IEnumerable<string> where each string contains the wanted part from one line of the file
It's not clear to me if you're after every fifth piece of text between the commas or if there are multiple lines and you want only the fifth piece of text on each line. So I've done both.
Every fifth piece of text:
var text = "1,2,3,4,i am some text,6,7,8,9"
+ ",10,11,12,13,14,15,16,17,18,19,20";
var everyFifth =
text
.Split(',')
.Where((x, n) => n % 5 == 4);
Only the fifth piece of text on each line:
var lines = new []
{
"1,2,3,4,i am some text,6,7",
"8,9,10,11,12,13,14,15",
"16,17,18,19,20",
};
var fifthOnEachLine =
lines
.Select(x => x.Split(',')[4]);
I have a text file that I am opening up and it is in a similar format to this:
10 SOME TEXT
20 T A40
B B5, C45, D48
30 B E25
40 B F17, G18
60 T H20, I23,
B J6, K7, L8, M9, N10, O11, P12,
Q31, R32, S33, T34, U35, V36,
W37, X38, Y39
100 T Z65
360 B A1, B4, C5, D6, E7, F10
2000 T SOME TEXT
423 TEXT
With this text I need to be able to read it and replace values accordingly. If a ReadLine begins with a number (ie, 10, 20, 30, 40, 60, 100, 360, 2000, 423) I need to to check if there is a T, B, or text after it. The only case that I need to change/reformat the lines when they come in and output them differently.
Example: 10 is fine except for I would like to add zeros in front of every number to make them 4 digits long (ie, 10 turns to 0010, 360 turns to 0360, 2000 stays the same). When the string "B B5, C45, D48" is read (this is the third line in the text) I need to change it to say "20A B5, C45, D48". I need to grab the number above the "B" and concat it to the "B" and replace the "B" with an "A". If instead of a "B" there is a "T" I simply need to remove the "T". Also, if a line does not start with a number or a "B" (ie, Q31 or W37) I need to concat that line with the previous line.
So after the changes take place it should look like this:
0010 SOME TEXT
0020 A40
0020A B5, C45, D48
0030A E25
0040A F17, G18
0060 H20, I23,
0060A J6, K7, L8, M9, N10, O11, P12, Q31, R32, S33, T34, U35, V36, W37, X38, Y39
0100 Z65
0360A A1, B4, C5, D6, E7, F10
2000 SOME TEXT
0423 TEXT
I am currently trying to use Regex to do this but I have been told that there is an easier way to do this and I am not sure how. So far I have been able to add the zeros in front of the numbers. Also, my code is adding an "A" to the end of everything as well as keeping the original number on the next line and I am not grabbing the lines that begin with anything but a digit.
This is what my current output is turning out to look like:
0010A
0010
0020A
0020
0030A
0030
0060A
0060
0100A
0100
0360A
0360
2000
2000
0423A
0423
I am obviously doing something wrong using Regex.
Here is my current code:
private void openRefsButton_Click(object sender, EventArgs e)
{
// Initialize the OpenFileDialog to specify the .txt extension as well as
// its intial directory for the file.
openRefs.DefaultExt = "*.txt";
openRefs.Filter = ".txt Files|*.txt";
openRefs.InitialDirectory = "C:\\";
openRefs.RestoreDirectory = true;
try
{
// Open the contents of the file into the originalTextRichTextBox.
if (openRefs.ShowDialog() == DialogResult.OK && openRefs.FileName.Length > 0)
refsTextRichTextBox.LoadFile(openRefs.FileName, RichTextBoxStreamType.PlainText);
// Throws a FileNotFoundException otherwise.
else
throw new FileNotFoundException();
StreamReader refsInput = File.OpenText(openRefs.FileName);
string regExpression = #"^[\d]+";
string findNewBottomRegex = #"^B\s";
StringBuilder buildNumberText = new StringBuilder();
StringBuilder formatMatchText = new StringBuilder();
foreach (string allLines in File.ReadAllLines(openRefs.FileName))
{
Match newBottomMatch = Regex.Match(allLines, findNewBottomRegex);
Match numberStartMatch = Regex.Match(allLines, regExpression);
int counter = 0;
if (counter < numberStartMatch.Length)
{
if (numberStartMatch.Value.Length == 2)
{
if (refsTextRichTextBox.Text.Contains(newBottomMatch.ToString()))
{
finalTextRichTextBox.AppendText("00" + numberStartMatch + "A\n");
}
finalTextRichTextBox.AppendText("00" + numberStartMatch + "\n");
}
else if (numberStartMatch.Value.Length == 3)
{
if (refsTextRichTextBox.Text.Contains(newBottomMatch.ToString()))
{
finalTextRichTextBox.AppendText("0" + numberStartMatch + "A\n");
}
finalTextRichTextBox.AppendText("0" + numberStartMatch + "\n");
}
else
{
if (refsTextRichTextBox.Text.Contains(newBottomMatch.ToString()))
{
finalTextRichTextBox.AppendText(numberStartMatch + "A\n");
}
finalTextRichTextBox.AppendText(numberStartMatch + "\n");
}
counter++;
}
}
}
// Catches an exception if the file was not opened.
catch (Exception)
{
MessageBox.Show("There was not a specified file path.", "Path Not Found Error",
MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
}
}
}
QUESTION(S):
What is a better way to go about doing this task?
Are there any recommendations on changing my code to be more efficient and cleaner?
How do I properly split each line into number, T/B, A40 when every line is not the same?
After the lines are properly split, how do I replace copy the line before if the current line begins with a "B"?
If the line begins with "Q31" or similar, how do I add that current line to the end of the previous one?
Once this happens, is there a way to concat everything to create the speficied format above?
WORK FLOW #jaywayco
Open Text File
Read file line by line
Save each line in a list of strings
Split each string by ' '
Find each line that starts with a digit
Replace that digit to make it 4 digits in length
Check the following text after the digit to see if it is a "B ", "T ", or "SOME TEXT"
if "B " copy the line above
Add an "A" to the end of the digit
if "T " remove the "T "
if "SOME TEXT" do nothing
Find each line that starts with a "B "
Copy the digits on the line above and concat to the front of the "B "
Follow step 4.b.i
Find each line that starts with (or similar to) "Q31"
Concat this line to the end of the previous line
...?
Here's a really lame, procedural solution:
using System.IO;
using System.Collections.Generic;
namespace ConsoleApplication
{
class Program
{
static void Main(string[] args)
{
var list = new List<string>();
using (var reader = File.OpenText(#"c:\input.txt"))
{
while (true)
{
var line = reader.ReadLine();
if (string.IsNullOrEmpty(line)) break;
list.Add(line);
}
}
list = HandleRemoveTRequirement(list);
list = HandleFourDigitRequirement(list);
list = HandleConcatRequirement(list);
list = HandleStartsWithBRequirement(list);
list = HandleSecondElementIsBRequirement(list);
using (var output = new StreamWriter(#"c:\output.txt"))
{
foreach (var line in list)
{
output.WriteLine(line);
}
}
}
static List<string> HandleSecondElementIsBRequirement(List<string> list)
{
var result = new List<string>();
foreach (var line in list)
{
var parts = line.Split(' ');
if (parts[1].Equals("B"))
{
parts[0] += "A";
parts[1] = string.Empty;
result.Add(string.Join(" ", parts).Replace(" ", " "));
}
else
{
result.Add(line);
}
}
return result;
}
static List<string> HandleStartsWithBRequirement(List<string> list)
{
var result = new List<string>();
var i = 0;
foreach (var line in list)
{
var parts = line.Split(' ');
if (parts[0].Equals("B"))
{
parts[0] = string.Empty;
result.Add(list[i - 1].Split(' ')[0] + "A" + string.Join(" ", parts));
}
else
{
result.Add(line);
}
i++;
}
return result;
}
static List<string> HandleConcatRequirement(List<string> list)
{
var result = new List<string>();
foreach (var line in list)
{
var parts = line.Split(' ');
int test;
if (int.TryParse(parts[0], out test) || parts[0].Equals("B"))
{
result.Add(line);
}
else
{
result[result.Count -1] += line;
}
}
return result;
}
static List<string> HandleRemoveTRequirement(List<string> list)
{
var result = new List<string>();
foreach (var line in list)
{
var parts = line.Split(' ');
if (parts[1].Equals("T"))
{
parts[1] = string.Empty;
}
result.Add(string.Join(" ", parts).Replace(" ", " "));
}
return result;
}
static List<string> HandleFourDigitRequirement(List<string> list)
{
var result = new List<string>();
foreach (var line in list)
{
var parts = line.Split(' ');
int test;
if (int.TryParse(parts[0], out test))
{
parts[0] = parts[0].PadLeft(4, '0');
result.Add(string.Join(" ", parts));
}
else
{
result.Add(line);
}
}
return result;
}
}
}
These are pretty complicated requirements and I would be tempted to implement this as a workflow. This way you can separate out each of the logical steps and this will increase maintainability.
I would be tempted to represent the text file as an array of string arrays or even a data table. Then you can write general functions that concatenate/transform specific values
One way to possibly approach this is similiar to jaywayco's.
I'd start with placing each line split by spaces into it's own array. Place that array into an Array of arrays. From there you can consider your workflow. Your line array that is split by the spaces you can determine how to print it based off the first value, being a number or letter B etc... If it's a B, you know that it should start with array[i-1] first value, which would be the number etc. You'd have to think through the logic a bit, but I think you can understand where I am coming from. I'm not sure if this is the best approach or not, but I think this is the way I would tackle it. Good luck!
Edit: Here is some mock code...
var mainArray = new Array[textFile.Count];
//obviously get the count of number of lines set that to the size of your array object.
for(int i=0; i < mainArray.Length; i++)
{
var line = methodToGetLineFromTextFile[i];
string[] lineArray = line.Split(' ');
mainArray[i] = lineArray;
}
//Once you have everything loaded into your arrays, apply your workflow logic.
Hope this helps!
The way I would go about this task is to write a set of unit tests based on your requirements, then make them pass one at a time (having one test per requirement).
As jaywayco suggested, I would read the file into an array of lines, then implement each of your rules as a line transformation method which can be tested in isolation. I would probably separate out the method which can select which transformation(s) to apply. Then loop over the lines and apply the transformations.