【问题标题】:Concat three strings from file when I find a match找到匹配项时从文件中连接三个字符串
【发布时间】:2017-10-02 07:41:36
【问题描述】:

我有这个应用程序,我在其中读取 .txt 文件的内容,如下所示:

- ...
- Nonsense
- Nonsense
- Nonsense
- Line 1
- Line 2
- Line 3
- Nonsense
- Nonsense
- Line1
- Line2
- Line3 
- Nonsense
- ... etc 

当我找到匹配的单词“第 1 行”时,我需要添加以下两行,以便得到以下结果

- Line1 Line2 Line3
- Line1 Line2 Line3

我使用流读取器和列表来获取第一个值的行,但是合并以下两行的最佳做法是什么? 到目前为止我的代码:

List<string> match = new List<string>();
string line;        

using (StreamReader inputStream = new StreamReader(txtInput))
        {
            while ((line = inputStream.ReadLine()) != null)
            {
                if (line.Contains("Line1"))
                {
                    match.Add(line);                        
                }
            }
        }

【问题讨论】:

  • 如果我理解正确,您不能使用match.Add(line + " " + inputStream.ReadLine() + " " + inputStream.ReadLine()) 将第二行和第三行附加到第一行吗?
  • 是的。我认为可以。
  • @Patrik - 我假设这些行实际上并不是以 - ?

标签: c# string concatenation


【解决方案1】:

像这样替换您的 while 循环将解决您的问题。

while ((line = inputStream.ReadLine()) != null)
                    {
                        string outputLine;
                        if (line.Contains("Line1"))
                        {

                            outputLine = line + inputStream.ReadLine() + inputStream.ReadLine();
                            match.Add(outputLine);
                        }

                    }

【讨论】:

  • 像魅力一样工作 :) 谢谢
【解决方案2】:

如果您安装 Microsoft 的交互式框架 (NuGet "System.Interactive"),那么您会得到一个方便的 IEnumerable&lt;T&gt; 扩展名,名为 Buffer。它会让你这样做:

List<string> match =
    File
        .ReadLines(txtInput)
        .Buffer(3, 1)
        .Where(x => x[0] == "Line1")
        .Select(x => String.Join(" ", x))
        .ToList();

就是这样。任务完成。

【讨论】:

    【解决方案3】:

    我建议不要使用StreamReader。如果您使用File.ReadAllLines(),您可以更轻松地遍历您的文本文件内容。并且您可以更轻松地检查“Line1”之后是否有以下两行。

    类似的东西

    var path = Path to the file;
    List<string> lines = File.ReadAllLines(path).ToList();
    List<string> matches = new List<string>();
    
    for(int i = 0; i < lines.Count; i++)
    {
        var line = lines[i];
        if(line.Equals("Line1"))
        {
            if (lines.Count > i + 2)
            {
                matches.Add(lines[i++]);
                matches.Add(lines[i++]);
                matches.Add(lines[i++]);
            }
        }
    }
    

    【讨论】:

    • 这是一个解决方案,但它脆弱且容易出错。 1)如果文本很长,用ReadAllLines将其全部存储在内存中是浪费的,甚至可能导致OutOfMemory异常;考虑取消ReadLines。 2) 如果输入格式错误并且文件以“第 2 行”结尾,会发生什么情况?另外,你为什么要创建List&lt;string&gt;ReadAllLines 返回的数组也可以正常工作。
    • 这就是我添加支票if (lines.Count &gt; i + 2)的原因。如果文本文件变得非常大,这将不是最好的解决方案;是的。但即使是包含 1000 万个符号的文本文件也不会超过 10 mb。所以我猜提问者会说他是否必须处理非常大的文件。
    • 糟糕,很抱歉错过了支票。
    【解决方案4】:

    使用 C# 7 的本地函数语法(无论如何都不是必需的),您可以执行以下操作:

    public IEnumerable<string> ProcessText(string txtInput)
    {
        IEnumerable<string> GetNextNLines(IEnumerator<string> enumerator, int n)
        {
            var counter = 0;
    
            while (counter < n && enumerator.MoveNext())
            {
                 yield return enumerator.Current;
                 counter += 1;
            }
    
            if (counter != n) //consider throwing with an unexpected format message.
        }
    
        using (var enumerator = File.ReadLines(txtInput).GetEnumerator())
        {
            while (enumerator.MoveNext())
            {
                if (enumerator.Current.Constains("Line1"))
                {
                    yield return enumerator.Current;
    
                    foreach (var line in GetNextNLines(enumerator, 2)
                    {
                        yield return line;
                    }
                } 
            }
        }
    }
    

    这种方法很懒惰,会避免预先读取整个文件,如果文件非常大,可能会导致问题。

    【讨论】:

      【解决方案5】:

      如果我正确理解了您的要求,您需要一个串联字符串列表,每个字符串是 3 行的串联,包括 Line 1 和下一行。使用流阅读器并稍微修改您的代码:

       List<string> match = new List<string>();
       string line;
      
       using (StreamReader inputStream = new StreamReader(txtInput))
       {
           int charctersLeftAfterMatch = -1;
           string temp = "";
           while ((line = inputStream.ReadLine()) != null)
           {
               // If first instance is found, update characters to pick up next 2
               if (line.Contains("Line1") || line.Contains("Line 1"))
               {
                    charctersLeftAfterMatch = 3;
                    temp = "";
               }
      
               // If last line (3rd) has been reached then add to collection
               // Else if lines are still left then concatenate and move ahead
               if (charctersLeftAfterMatch-- == 1)
               {
                    temp += line;
                    match.Add(temp);
               }
               else if (charctersLeftAfterMatch > 0)
               {
                    temp += line;
               }
           }
      }
      
      // Match contains 2 string's: 
      // [0] Line 1 Line 2 Line 3
      // [1] Line1 Line2 Line3
      

      另外,请注意您在第一种情况下使用Line 1,在下一次使用Line1。如果修改.Contains() 条件以将两者都考虑在内。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2015-05-20
        • 2015-01-31
        • 2020-10-08
        • 1970-01-01
        • 1970-01-01
        • 2015-10-11
        • 2014-02-11
        相关资源
        最近更新 更多