最好的方式来分割字符串转换成线(Best way to split string into line

2019-07-20 13:08发布

你如何分割多线串入行?

我知道这种方式

var result = input.Split("\n\r".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);

看起来有点难看,失去空行。 有没有更好的解决办法?

Answer 1:

  • 如果长相难看,只是删除不必要的ToCharArray电话。

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

    • 使用数组文本-但是这会给你空行的Windows风格的行尾\r\n

       var result = text.Split(new [] { '\r', '\n' }); 
    • 使用正则表达式,由Bart所示:

       var result = Regex.Split(text, "\r\n|\r|\n"); 
  • 如果您想保留空行,你为什么要明确地告诉C#把它们扔掉? ( StringSplitOptions参数) -使用StringSplitOptions.None代替。



Answer 2:

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


Answer 3:

你可以使用Regex.Split:

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

编辑:增加|\r占(以上)的Mac行终止。



Answer 4:

更新:请参见这里的替代/异步解决方案。


这个伟大的工程,比正则表达式快:

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

有重要的是"\r\n" ,使得它作为一个换行符,首先在数组中。 以上给出了相同的结果,这两种正则表达式的解决方案:

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

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

除了正则表达式的结果是大约慢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")
);

输出:

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

用法:

input.GetLines()      // keeps empty lines

input.GetLines(true)  // removes empty lines


Answer 5:

如果你想保持空行只是删除StringSplitOptions。

var result = input.Split(System.Environment.NewLine.ToCharArray());


Answer 6:

我有这个其他的答案 ,但是这一次,根据杰克的答案 , 是显著较快可能是首选,因为它以异步方式工作,虽然速度稍慢。

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

用法:

input.GetLines()      // keeps empty lines

input.GetLines(true)  // removes empty lines

测试:

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()
);

输出:

00:00:03.9603894

00:00:00.0029996

00:00:04.8221971



Answer 7:

稍扭曲,但迭代器块做到这一点:

public static IEnumerable<string> Lines(this string Text)
{
    int cIndex = 0;
    int nIndex;
    while ((nIndex = Text.IndexOf(Environment.NewLine, cIndex + 1)) != -1)
    {
        int sIndex = (cIndex == 0 ? 0 : cIndex + 1);
        yield return Text.Substring(sIndex, nIndex - sIndex);
        cIndex = nIndex;
    }
    yield return Text.Substring(cIndex + 1);
}

然后,您可以拨打:

var result = input.Lines().ToArray();


Answer 8:

      char[] archDelim = new char[] { '\r', '\n' };
      words = asset.text.Split(archDelim, StringSplitOptions.RemoveEmptyEntries); 


Answer 9:

    private string[] GetLines(string text)
    {

        List<string> lines = new List<string>();
        using (MemoryStream ms = new MemoryStream())
        {
            StreamWriter sw = new StreamWriter(ms);
            sw.Write(text);
            sw.Flush();

            ms.Position = 0;

            string line;

            using (StreamReader sr = new StreamReader(ms))
            {
                while ((line = sr.ReadLine()) != null)
                {
                    lines.Add(line);
                }
            }
            sw.Close();
        }



        return lines.ToArray();
    }


Answer 10:

这是棘手,妥善处理行结束。 正如我们所知,该行结束符可以是“换行”(ASCII 10, \n\x0A\u000A ), “回车”(ASCII 13, \r\x0D\u000D ),或一些组合他们。 让我们再回到DOS,Windows使用两个字符序列CR-LF \u000D\u000A ,所以这个组合应该仅发出一个单一的线。 UNIX使用一个单一的\u000A ,很老的Mac电脑使用单个\u000D字符。 到一个文本文件中把这些字符的任意混合物的标准方法如下:

  • 每个CR或LF字符应该跳过, 除了下一行...
  • ...如果一个CR后面紧接着LF( \u000D\u000A )那么这两个一起跳过只有一行。
  • String.Empty是返回没有线唯一的输入(任何字符需要至少一条线)
  • 最后一行必须返回即使它有没有CR也不LF。

前述规则描述的行为StringReader.ReadLine及相关函数,和如下所示的函数产生相同的结果。 它是一个高效的C#断线功能忠实地实现了这些准则,以正确处理CR / LF的任意序列或组合。 所列举的行不包含任何CR / LF字符。 空行被保留下来,并返回String.Empty

/// <summary>
/// Enumerates the text lines from the string, handling mixed CR-LF scenarios correctly.
/// </summary>
public static IEnumerable<String> Lines(this String s)
{
    int j = 0, c, i;
    char ch;
    if ((c = s.Length) > 0)
        do
        {
            for (i = j; (ch = s[j]) != '\r' && ch != '\n' && ++j < c;)
                ;

            yield return s.Substring(i, j - i);
        }
        while (++j < c && (ch != '\r' || s[j] != '\n' || ++j < c));
}

注意:如果你不介意创建的开销StringReader每个呼叫实例,可以使用下面的C#代码7代替。 如所指出的,虽然上面的例子中可以稍微更有效,这两种功能产生完全相同的结果。

public static IEnumerable<String> Lines(this String s)
{
    using (var tr = new StringReader(s))
        while (tr.ReadLine() is String L)
            yield return L;
}


文章来源: Best way to split string into lines