C# - 读取/复制/替换文本中的行
我正在打开一个文本文件,它的格式与此类似:
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
使用此文本,我需要能够读取它并相应地替换值。如果 ReadLine 以数字开头(即 10、20、30、40、60、100、360、2000、423),我需要检查后面是否有 T、B 或文本。唯一的情况是,当行进入并以不同方式输出时,我需要更改/重新格式化行。
示例:10 很好,只是我想在每个数字前面添加零,使它们成为 4 位数字(即 10 次变为 0010,360 次变为 0360,2000 保持不变)。当读取字符串“B B5,C45,D48”时(这是文本中的第三行),我需要将其更改为“20A B5,C45,D48”。我需要获取“B”上方的数字并将其连接到“B”,然后将“B”替换为“A”。如果不是“B”而是“T”,我只需删除“T”即可。另外,如果一行不以数字或“B”(即 Q31 或 W37)开头,我需要将该行与上一行连接起来。
因此,更改发生后,它应该如下所示:
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
我目前正在尝试使用正则表达式来执行此操作,但有人告诉我有一种更简单的方法可以执行此操作我不知道怎么做。到目前为止,我已经能够在数字前面添加零。另外,我的代码在所有内容的末尾添加一个“A”,并将原始数字保留在下一行,并且我不会抓取以数字以外的任何内容开头的行。
这就是我当前的输出结果:
0010A
0010
0020A
0020
0030A
0030
0060A
0060
0100A
0100
0360A
0360
2000
2000
0423A
0423
我显然使用正则表达式做错了一些事情。
这是我当前的代码:
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);
}
}
}
}
问题:
- 完成此任务的更好方法是什么?
- 对于更改我的代码以使其更高效、更简洁,有什么建议吗?
- 当每行不相同时,如何正确地将每一行拆分为数字、T/B、A40?
- 正确分割行后,如果当前行以“B”开头,如何替换复制之前的行?
- 如果该行以“Q31”或类似内容开头,如何将当前行添加到上一行的末尾?
- 一旦发生这种情况,有没有办法连接所有内容以创建上面指定的格式?
工作流程@jaywayco
- 打开文本文件
- 逐行读取文件
- 将每一行保存在字符串列表中
- 用 ' ' 分割每个字符串
- 查找以数字开头的每一行
- 替换该数字,使其长度为 4 位
- 检查数字后的以下文本,看看它是否是“B”、“T”或“SOME TEXT”
- 如果“B”复制上面的行
- 在数字末尾添加“A”
- 如果“T”删除“T”
- 如果“SOME TEXT”不执行任何操作
- 如果“B”复制上面的行
- 查找以“B”开头的每一行
- 复制上一行的数字并连接到“B”前面
- 按照步骤 4.bi 进行操作
- 复制上一行的数字并连接到“B”前面
- 查找以(或类似)“Q31”开头的每一行
- 将此行连接到上一行的末尾
- ...?
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
- if "B " copy the line above
- 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
- Copy the digits on the line above and concat to the front of the "B "
- Find each line that starts with (or similar to) "Q31"
- Concat this line to the end of the previous line
- ...?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
这是一个非常蹩脚的程序解决方案:
Here's a really lame, procedural solution:
这些都是非常复杂的要求,我很想将其作为工作流程来实现。通过这种方式,您可以分离出每个逻辑步骤,这将提高可维护性。
我很想将文本文件表示为字符串数组的数组,甚至数据表。然后您可以编写连接/转换特定值的通用函数
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
一种可能解决此问题的方法类似于 jaywayco 的方法。
我首先将用空格分隔的每一行放入它自己的数组中。将该数组放入数组的数组中。从那里您可以考虑您的工作流程。你的行数组被空格分割,你可以根据第一个值确定如何打印它,是数字或字母 B 等......如果它是 B,你知道它应该以 array[i-1] 开头第一个值,即数字等。您必须稍微思考一下逻辑,但我认为您可以理解我的来源。我不确定这是否是最好的方法,但我认为这是我解决这个问题的方法。祝你好运!
编辑:这是一些模拟代码...
希望这有帮助!
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...
Hope this helps!
我执行此任务的方法是根据您的要求编写一组单元测试,然后让它们一次通过一个测试(每个要求一个测试)。
正如 jaywayco 建议的那样,我会将文件读入行数组,然后将每个规则实现为可以单独测试的行转换方法。我可能会分离出可以选择要应用的转换的方法。然后循环这些线并应用转换。
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.