如何从格式化的字符串中删除空行

42

如何在C#中删除字符串中的空行?

我正在使用C#(Windows Forms)生成一些文本文件,但出现了一些空行。如何在生成字符串后将它们删除(使用StringBuilderTextWriter)。

示例文本文件:

THIS IS A LINE



THIS IS ANOTHER LINE AFTER SOME EMPTY LINES!

1
你真的想要在生成后删除这些行吗?我认为你应该看看为什么会生成额外的行。如果你使用WriteLine(...)方法,它们会自动为你写入新行。而Write(...)方法则不会写入新行序列。 - Mesh
1
这不是我的错,我正在从一些文本文件中提取文本,这就是问题所在! - Dumbo
https://dev59.com/sm445IYBdhLWcg3wOnvW#4974031 - Allen
https://dev59.com/kW855IYBdhLWcg3wy3oc - Stefan27
11个回答

106

如果您还想删除只包含空格的行,请使用

resultString = Regex.Replace(subjectString, @"^\s+$[\r\n]*", string.Empty, RegexOptions.Multiline);

^\s+$ 将删除从第一个空行到最后一个连续的空行(包括仅包含制表符或空格的行)之间的所有内容。

[\r\n]* 然后将删除最后的CRLF(或者只是LF,这很重要,因为.NET正则表达式引擎会将$匹配到\r\n之间,非常有趣)。


3
几乎可以实现,但我有一个问题:最后一行为空,却没有被移除。因为我不太擅长正则表达式,所以不确定原因。 - Robin Rye
5
这是因为至少需要一个空白字符才能匹配。如果你将\s+改成\s*,那么它也应该会删除最后一行。 - Tim Pietzcker
5
谢谢Tim,我在研究正则表达式后也是这样想的,但并没有帮助。我改为使用\s*,但最后一行仍留在结果字符串中。我使用了str.Trim()来去掉它。 - Robin Rye
1
这也会移除最后一个空行:Regex.Replace(subjectString, @"[\r\n]^\s$[\r\n]*", "", RegexOptions.Multiline); - Diana
1
@Diana:这可能会有副作用。在某些情况下,使用此方法会删除太多的“换行符”。 - roland
显示剩余4条评论

22

Tim Pietzcker - it对我没用。我需要做一些小改动,但还是谢谢!

额,C#正则表达式.. 我又不得不做出改变,但现在它运行良好:

private string RemoveEmptyLines(string lines)
{
  return Regex.Replace(lines, @"^\s*$\n|\r", string.Empty, RegexOptions.Multiline).TrimEnd();
}

Example: http://regex101.com/r/vE5mP1/2


12

您可以尝试使用 String.Replace("\n\n", "\n");


好的,谢谢,但这不是一个通用解决方案,不会包括制表符、空格和其他类似的内容。 - Dumbo
21
你的问题没有提到那个。事实上,你明确说了“空行”。 - user807566
我也加上了 Trim()。但是,对于 \n\n\n 这种情况仍然无法工作。 - HappyNomad
那并不能解决所有空行的问题。我遇到了这样一种情况,即有可变数量的换行符连在一起。因此,在这种情况下,我们需要多次迭代文本。 - Arsinclair

4

请尝试以下操作

Regex.Replace(subjectString, @"^\r?\n?$", "", RegexOptions.Multiline);

3
private string remove_space(string st)
{
    String final = "";

    char[] b = new char[] { '\r', '\n' };
    String[] lines = st.Split(b, StringSplitOptions.RemoveEmptyEntries);
    foreach (String s in lines)
    {
        if (!String.IsNullOrWhiteSpace(s))
        {
            final += s;
            final += Environment.NewLine;
        }
    }

    return final;
}

please add description - zohar
你在这里存在性能问题。考虑使用一个包含100万个\n的字符串来测试你的方法。考虑使用 StringBuilder 替代 +String。我认为将你的函数命名为 RemoveEmptyLines 更合理。 - AaA
需要解释一下。 - Peter Mortensen

1

1
private static string RemoveEmptyLines(string text)
{
    var lines = text.Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);

    var sb = new StringBuilder(text.Length);

    foreach (var line in lines)
    {
        sb.AppendLine(line);
    }

    return sb.ToString();
}

AppendLine 在返回的字符串末尾添加一个空行。 - thomasgalliker
@thomasgalliker,这是意图。split会删除行末的换行符,因此您需要将其添加回去,否则所有行都会混在一起!唯一的问题是Environment.NewLine是一个字符串,无法适应字符数组。 - AaA

1

这里提到的方法都没有完全帮助我解决问题,但我找到了一种解决方法。

  1. Split text to lines - collection of strings (with or without empty strings, also Trim() each string).

  2. Add these lines to multiline string.

     public static IEnumerable<string> SplitToLines(this string inputText, bool removeEmptyLines = true)
     {
         if (inputText == null)
         {
             yield break;
         }
    
         using (StringReader reader = new StringReader(inputText))
         {
             string line;
             while ((line = reader.ReadLine()) != null)
             {
                 if (removeEmptyLines && !string.IsNullOrWhiteSpace(line))
                     yield return line.Trim();
                 else
                     yield return line.Trim();
             }
         }
     }
    
     public static string ToMultilineText(this string text)
     {
         var lines = text.SplitToLines();
    
         return string.Join(Environment.NewLine, lines);
     }
    

1

基于Evgeny Sobolev的代码,我编写了这个扩展方法,它还使用TrimEnd(TrimNewLineChars)修剪了最后一个(过时的)换行符:

public static class StringExtensions
{
    private static readonly char[] TrimNewLineChars = Environment.NewLine.ToCharArray();

    public static string RemoveEmptyLines(this string str)
    {
        if (str == null)
        {
            return null;
        }

        var lines = str.Split(TrimNewLineChars, StringSplitOptions.RemoveEmptyEntries);

        var stringBuilder = new StringBuilder(str.Length);

        foreach (var line in lines)
        {
            stringBuilder.AppendLine(line);
        }

        return stringBuilder.ToString().TrimEnd(TrimNewLineChars);
    }
}

1
你的扩展只在字符串来源于同一系统时起作用。如果字符串在不同系统之间传输,例如从Linux、Web到Windows,则根本不起作用。考虑将TrimNewLineChars更改为实际数组。 - AaA
我不知道你的意思。你可以贴出一个它无法工作的字符串吗?我将用它编写单元测试。谢谢。 - thomasgalliker
请在文本文件上尝试,其中“行尾序列”为CR + LF(Windows),LF(Linux)和Mac(经典版,在Max OS X之前)(CR)。 CR = ASCII 13。 LF = ASCII 10。 - Peter Mortensen
这就是AaA所提示的。Environment.NewLine只有在使用当前系统的默认行尾序列创建文件时才有效。大多数高级文本编辑器都可以处理/设置/保存格式(在Visual Studio Code中,您可以通过某种隐藏功能单击显示的设置(例如,“LF”)来更改给定文件的行尾序列)。 - Peter Mortensen
请在投票之前仔细阅读问题。不要轻易投反对票。 - thomasgalliker

0

我尝试了之前的答案,但其中一些使用正则表达式的并不能正常工作。

如果你使用正则表达式来查找空行,那么你不能用同样的方法来删除。

因为它会删除非空行中的“换行符”。

你必须使用“正则表达式组”来进行替换。

这里有一些其他不使用正则表达式的答案可能会有性能问题。

    private string remove_empty_lines(string text) {
        StringBuilder text_sb = new StringBuilder(text);
        Regex rg_spaces = new Regex(@"(\r\n|\r|\n)([\s]+\r\n|[\s]+\r|[\s]+\n)");
        Match m = rg_spaces.Match(text_sb.ToString());
        while (m.Success) {
            text_sb = text_sb.Replace(m.Groups[2].Value, "");
            m = rg_spaces.Match(text_sb.ToString());
        }
        return text_sb.ToString().Trim();
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接