将字符串拆分为行的最佳方法

Kon*_*rin 131 c# string syntax multiline

如何将多行字符串拆分成行?

我知道这种方式

var result = input.Split("\n\r".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
Run Code Online (Sandbox Code Playgroud)

看起来有点难看,失去空行.有更好的解决方案吗?

Kon*_*lph 161

  • 如果它看起来很难看,只需删除不必要的ToCharArray电话.

  • 如果你想要么拆分\n或者\r,你有两个选择:

  • 如果你想保留空行,为什么要明确告诉C#扔掉它们?(StringSplitOptions参数) - StringSplitOptions.None改用.

  • 包含'\ r \n\r \n'的文本怎么样?string.Split将返回4个空行,但是使用'\ r \n'它应该给2.如果'\ r \n'和'\ r'混合在一个文件中会变得更糟. (7认同)
  • 删除ToCharArray将使代码特定于平台(NewLine可以是'\n') (2认同)
  • @Hamish好吧,只需查看枚举的文档,或查看原始问题!是`StringSplitOptions.RemoveEmptyEntries`。 (2认同)
  • @SurikovPavel 使用正则表达式。这绝对是首选变体,因为它可以正确地与任何行结尾组合一起使用。 (2认同)

Jac*_*ack 117

using (StringReader sr = new StringReader(text)) {
    string line;
    while ((line = sr.ReadLine()) != null) {
        // do something
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 在我的主观意见中,这是最干净的方法. (11认同)
  • 关于性能(相对于string.Split或Regex.Split)有什么想法吗? (3认同)

ora*_*rad 41

更新:请参阅此处了解替代/异步解决方案.


这很好,比Regex更快:

input.Split(new[] {"\r\n", "\r", "\n"}, StringSplitOptions.None)
Run Code Online (Sandbox Code Playgroud)

重要的是"\r\n"在数组中首先使它成为一个换行符.以上结果与这些Regex解决方案的结果相同:

Regex.Split(input, "\r\n|\r|\n")

Regex.Split(input, "\r?\n|\r")
Run Code Online (Sandbox Code Playgroud)

除了Regex的速度慢了大约10倍.这是我的测试:

Action<Action> measure = (Action func) => {
    var start = DateTime.Now;
    for (int i = 0; i < 100000; i++) {
        func();
    }
    var duration = DateTime.Now - start;
    Console.WriteLine(duration);
};

var input = "";
for (int i = 0; i < 100; i++)
{
    input += "1 \r2\r\n3\n4\n\r5 \r\n\r\n 6\r7\r 8\r\n";
}

measure(() =>
    input.Split(new[] {"\r\n", "\r", "\n"}, StringSplitOptions.None)
);

measure(() =>
    Regex.Split(input, "\r\n|\r|\n")
);

measure(() =>
    Regex.Split(input, "\r?\n|\r")
);
Run Code Online (Sandbox Code Playgroud)

输出:

00:00:03.8527616

00:00:31.8017726

00:00:32.5557128

这是扩展方法:

public static class StringExtensionMethods
{
    public static IEnumerable<string> GetLines(this string str, bool removeEmptyLines = false)
    {
        return str.Split(new[] { "\r\n", "\r", "\n" },
            removeEmptyLines ? StringSplitOptions.RemoveEmptyEntries : StringSplitOptions.None);
    }
}
Run Code Online (Sandbox Code Playgroud)

用法:

input.GetLines()      // keeps empty lines

input.GetLines(true)  // removes empty lines
Run Code Online (Sandbox Code Playgroud)

  • @OmegaMan怎么样'Hello \n \nworld \n \n`是一个边缘案例?它显然是一行文本,后面是空行,后面是另一行文本,后面是空行. (3认同)

Bar*_*ers 36

你可以使用Regex.Split:

string[] tokens = Regex.Split(input, @"\r?\n|\r");
Run Code Online (Sandbox Code Playgroud)

编辑:添加|\r到(较旧的)Mac线路终结器的帐户.

  • @Konrad Rudolph:AFAIK,'\ r'用于非常古老的MacOS系统,几乎从未遇到过.但是如果OP需要考虑它(或者我错了),那么正则可以很容易地扩展正则表达式来解释它:\ r?\n |\r \n (2认同)

Jon*_*röm 9

如果要保留空行,只需删除StringSplitOptions即可.

var result = input.Split(System.Environment.NewLine.ToCharArray());
Run Code Online (Sandbox Code Playgroud)

  • NewLine可以是'\n',输入文本可以包含"\n\r". (2认同)

小智 6

string[] lines = input.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
Run Code Online (Sandbox Code Playgroud)


ora*_*rad 5

我有另一个答案,但基于 Jack 的答案,这个答案明显更快,可能更受欢迎,因为它异步工作,尽管速度稍慢。

public static class StringExtensionMethods
{
    public static IEnumerable<string> GetLines(this string str, bool removeEmptyLines = false)
    {
        using (var sr = new StringReader(str))
        {
            string line;
            while ((line = sr.ReadLine()) != null)
            {
                if (removeEmptyLines && String.IsNullOrWhiteSpace(line))
                {
                    continue;
                }
                yield return line;
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

用法:

input.GetLines()      // keeps empty lines

input.GetLines(true)  // removes empty lines
Run Code Online (Sandbox Code Playgroud)

测试:

Action<Action> measure = (Action func) =>
{
    var start = DateTime.Now;
    for (int i = 0; i < 100000; i++)
    {
        func();
    }
    var duration = DateTime.Now - start;
    Console.WriteLine(duration);
};

var input = "";
for (int i = 0; i < 100; i++)
{
    input += "1 \r2\r\n3\n4\n\r5 \r\n\r\n 6\r7\r 8\r\n";
}

measure(() =>
    input.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.None)
);

measure(() =>
    input.GetLines()
);

measure(() =>
    input.GetLines().ToList()
);
Run Code Online (Sandbox Code Playgroud)

输出:

00:00:03.9603894

00:00:00.0029996

00:00:04.8221971

  • 我确实想知道这是否是因为您实际上没有检查枚举器的结果,因此它没有被执行。可惜我懒得去查。 (2认同)