代码之家  ›  专栏  ›  技术社区  ›  Neil C. Obremski

在C/.NET中强制使用CRLF的快速方法是什么?

  •  40
  • Neil C. Obremski  · 技术社区  · 16 年前

    如何将字符串中的所有新行序列规范化为一种类型?

    我想把所有的CRLF都做成电子邮件(mime文档)。理想情况下,这将被包装在静态方法中,执行速度非常快,并且不使用正则表达式(因为换行符、回车等的方差是有限的)。也许我忽略了一个BCL方法?

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

    5 回复  |  直到 7 年前
        1
  •  58
  •   Daniel Brückner    16 年前
    input.Replace("\r\n", "\n").Replace("\r", "\n").Replace("\n", "\r\n")
    

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

        2
  •  29
  •   Jon Skeet    16 年前

    这取决于 确切地 要求是什么。尤其是,您希望如何单独处理“\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();
        }
    }
    
        3
  •  5
  •   Zotta    10 年前

    简单变型:

    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");
    
        4
  •  4
  •   Nathan    16 年前
    string nonNormalized = "\r\n\n\r";
    
    string normalized = nonNormalized.Replace("\r", "\n").Replace("\n", "\r\n");
    
        5
  •  0
  •   Roberto B    7 年前

    我是说,这是一个快速的方法。

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

    所以搜索直接在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。