Подтвердить что ты не робот

Что такое быстрый способ заставить CRLF в С#/.NET?

Как бы вы нормализовали все строки новой строки в строке одному типу?

Я хочу сделать все CRLF для электронной почты (MIME-документы). В идеале это будет обернуто статическим методом, выполняется очень быстро и не будет использовать регулярные выражения (поскольку ограничения на разрывы строк, возврат каретки и т.д. Ограничены). Возможно, есть даже метод BCL, который я забыл?

ПРЕДПОЛОЖЕНИЕ: После того, как мы немного подумали, я думаю, что это безопасное предположение, что CR являются либо автономными, либо частью последовательности CRLF. То есть, если вы видите CRLF, тогда вы знаете, что все CR могут быть удалены. В противном случае трудно сказать, сколько строк должно выходить из чего-то типа "\ r\n\n\r".

4b9b3361

Ответ 1

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

Это будет работать, если вход содержит только один тип разрывов строк - либо CR, либо LF, либо CR + LF.

Ответ 2

Это зависит от того, что именно. В частности, как вы относитесь к "\ 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

string nonNormalized = "\r\n\n\r";

string normalized = nonNormalized.Replace("\r", "\n").Replace("\n", "\r\n");

Ответ 4

Простой вариант:

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

Ответ 5

Это быстрый способ сделать это, я имею в виду.

Он не использует дорогостоящую функцию регулярного выражения. Он также не использует несколько функций замены, каждый из которых индивидуально проделывал данные с несколькими проверками, выделениями и т.д.

Таким образом, поиск выполняется непосредственно в 1 для цикла. Для количества попыток увеличения емкости массива результатов цикл также используется в функции Array.Copy. Это все петли. В некоторых случаях более высокий размер страницы может быть более эффективным.

public static string NormalizeNewLine(this string val) {
    if (string.IsNullOrWhiteSpace(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' фактически не используется на базовых платформах. но: кто будет использовать два типа разрывов строк подряд, чтобы указать 2 строки? Если вы хотите это знать, вам нужно сначала взглянуть, чтобы узнать, используются ли \n и\r в отдельном документе в одном документе.