C#-读取/复制/替换文本中的行

本文关键字:文本 替换 读取 复制 C#- | 更新日期: 2023-09-27 18:00:37

我有一个正在打开的文本文件,它的格式与以下类似:

  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"。如果有一个"T"而不是"B",我只需要去掉"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

我目前正在尝试使用Regex来做到这一点,但有人告诉我有一种更简单的方法可以做到,我不确定如何做到。到目前为止,我已经能够在数字前面加零了。此外,我的代码是在所有内容的末尾添加一个"A",并将原始数字保留在下一行,我不会抓取以数字开头的行。

这就是我当前的输出结果:

    0010A 
    0010
    0020A 
    0020
    0030A 
    0030
    0060A 
    0060

    0100A 
    0100
    0360A 
    0360
    2000
    2000
    0423A 
    0423

我使用Regex显然是做错了什么。

这是我当前的代码:

    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"还是"某些文本"
      • 如果"B",复制上面的行
        • 在数字末尾加一个"A"
      • 如果"T"删除"T"
      • 如果"某些文本"无效
  • 查找以"B"开头的每一行
    • 复制上面一行的数字,并将其凹入"B"的前面
      • 按照步骤4.b.i
  • 查找以(或类似于)"Q31"开头的每一行
    • 将这一行凹到上一行的末尾

C#-读取/复制/替换文本中的行

这里有一个非常蹩脚的过程性解决方案:

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;
        }
    }
}

这些都是非常复杂的需求,我很想将其作为一个工作流来实现。通过这种方式,您可以分离出每个逻辑步骤,这将提高可维护性。

我很想把文本文件表示为字符串数组,甚至是数据表。然后,您可以编写连接/转换特定值的通用函数

一种可能的方法类似于jaywayco的方法。

我会先把每一行用空格分隔成自己的数组。将该数组放入数组数组中。从那里你可以考虑你的工作流程。你的行数组被空格分割,你可以根据第一个值(数字或字母B等)来决定如何打印它。如果它是B,你知道它应该以array[i-1]第一个值开始,也就是数字等。你必须仔细思考一下逻辑,但我想你能理解我的来源。我不确定这是否是最好的方法,但我认为这是我解决问题的方法。祝你好运!

编辑:这是一些模拟代码。。。

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.

希望这能有所帮助!

我完成这项任务的方法是根据您的需求编写一组单元测试,然后让它们一次通过一个(每个需求有一个测试)。

正如jaywayco所建议的,我会将文件读取成一个行数组,然后将每个规则实现为一个行转换方法,该方法可以单独测试。我可能会分离出可以选择应用哪些转换的方法。然后在线条上循环并应用变换。