55

您如何将字符串中的所有换行序列标准化为一种类型?

为了电子邮件(MIME 文档)的目的,我希望将它们全部设为 CRLF。理想情况下,这将被包装在一个静态方法中,执行速度非常快,并且不使用正则表达式(因为换行符、回车符等的差异是有限的)。也许我甚至忽略了一种 BCL 方法?

假设:在考虑了这一点之后,我认为说 CR 要么是独立的,要么是 CRLF 序列的一部分,这是一个安全的假设。也就是说,如果您看到 CRLF,那么您就知道可以删除所有 CR。否则很难判断应该从“\r\n\n\r”之类的内容中产生多少行。

4

6 回答 6

76
input.Replace("\r\n", "\n").Replace("\r", "\n").Replace("\n", "\r\n")

如果输入仅包含一种类型的换行符 - CR、LF 或 CR+LF,这将起作用。

于 2009-05-08T19:32:53.173 回答
32

这取决于具体的要求。特别是,您想如何自己处理“\r”?这应该算作换行符吗?例如,应该如何处理“a\n\rb”?那是一个非常奇怪的换行符,一个“\n”换行符,然后是一个流氓“\r”,还是两个单独的换行符?如果“\r”和“\n”都可以单独作为换行符,为什么“\r\n”不应该被视为两个换行符?

这是一些我怀疑相当有效的代码。

using System;
using System.Text;

class LineBreaks
{    
    static void Main()
    {
        Test("a\nb");
        Test("a\nb\r\nc");
        Test("a\r\nb\r\nc");
        Test("a\rb\nc");
        Test("a\r");
        Test("a\n");
        Test("a\r\n");
    }

    static void Test(string input)
    {
        string normalized = NormalizeLineBreaks(input);
        string debug = normalized.Replace("\r", "\\r")
                                 .Replace("\n", "\\n");
        Console.WriteLine(debug);
    }

    static string NormalizeLineBreaks(string input)
    {
        // Allow 10% as a rough guess of how much the string may grow.
        // If we're wrong we'll either waste space or have extra copies -
        // it will still work
        StringBuilder builder = new StringBuilder((int) (input.Length * 1.1));

        bool lastWasCR = false;

        foreach (char c in input)
        {
            if (lastWasCR)
            {
                lastWasCR = false;
                if (c == '\n')
                {
                    continue; // Already written \r\n
                }
            }
            switch (c)
            {
                case '\r':
                    builder.Append("\r\n");
                    lastWasCR = true;
                    break;
                case '\n':
                    builder.Append("\r\n");
                    break;
                default:
                    builder.Append(c);
                    break;
            }
        }
        return builder.ToString();
    }
}
于 2009-05-08T19:38:04.987 回答
9

简单变体:

Regex.Replace(input, @"\r\n|\r|\n", "\r\n")

为了获得更好的性能:

static Regex newline_pattern = new Regex(@"\r\n|\r|\n", RegexOptions.Compiled);
[...]
    newline_pattern.Replace(input, "\r\n");
于 2015-05-20T15:53:13.800 回答
4
string nonNormalized = "\r\n\n\r";

string normalized = nonNormalized.Replace("\r", "\n").Replace("\n", "\r\n");
于 2009-05-08T19:28:13.700 回答
1

我的意思是,这是一种快速的方法。

它不使用昂贵的正则表达式函数。它也不使用多个替换函数,每个替换函数都通过多次检查、分配等对数据进行循环。

所以搜索直接在一个for循环中完成。对于必须增加结果数组容量的次数,Array.Copy函数内也使用了循环。这就是所有的循环。在某些情况下,更大的页面大小可能更有效。

public static string NormalizeNewLine(this string val)
{
    if (string.IsNullOrEmpty(val))
        return val;

    const int page = 6;
    int a = page;
    int j = 0;
    int len = val.Length;
    char[] res = new char[len];

    for (int i = 0; i < len; i++)
    {
        char ch = val[i];

        if (ch == '\r')
        {
            int ni = i + 1;
            if (ni < len && val[ni] == '\n')
            {
                res[j++] = '\r';
                res[j++] = '\n';
                i++;
            }
            else
            {
                if (a == page) // Ensure capacity
                {
                    char[] nres = new char[res.Length + page];
                    Array.Copy(res, 0, nres, 0, res.Length);
                    res = nres;
                    a = 0;
                }

                res[j++] = '\r';
                res[j++] = '\n';
                a++;
            }
        }
        else if (ch == '\n')
        {
            int ni = i + 1;
            if (ni < len && val[ni] == '\r')
            {
                res[j++] = '\r';
                res[j++] = '\n';
                i++;
            }
            else
            {
                if (a == page) // Ensure capacity
                {
                    char[] nres = new char[res.Length + page];
                    Array.Copy(res, 0, nres, 0, res.Length);
                    res = nres;
                    a = 0;
                }

                res[j++] = '\r';
                res[j++] = '\n';
                a++;
            }
        }
        else
        {
            res[j++] = ch;
        }
    }

    return new string(res, 0, j);
}

我现在 '\n\r' 实际上并没有在基本平台上使用。但是谁会连续使用两种换行符来表示两个换行符呢?

如果你想知道,那么你需要先看看 \n 和 \r 是否在同一个文档中分别使用。

于 2017-11-17T11:17:35.560 回答
1

环境.新线;

包含“\r\n”的字符串用于非 Unix 平台,或包含“\n”的字符串用于 Unix 平台。

于 2020-07-10T14:13:57.270 回答