Ответ 1
input.Replace("\r\n", "\n").Replace("\r", "\n").Replace("\n", "\r\n")
Это будет работать, если вход содержит только один тип разрывов строк - либо CR, либо LF, либо CR + LF.
Как бы вы нормализовали все строки новой строки в строке одному типу?
Я хочу сделать все CRLF для электронной почты (MIME-документы). В идеале это будет обернуто статическим методом, выполняется очень быстро и не будет использовать регулярные выражения (поскольку ограничения на разрывы строк, возврат каретки и т.д. Ограничены). Возможно, есть даже метод BCL, который я забыл?
ПРЕДПОЛОЖЕНИЕ: После того, как мы немного подумали, я думаю, что это безопасное предположение, что CR являются либо автономными, либо частью последовательности CRLF. То есть, если вы видите CRLF, тогда вы знаете, что все CR могут быть удалены. В противном случае трудно сказать, сколько строк должно выходить из чего-то типа "\ r\n\n\r".
input.Replace("\r\n", "\n").Replace("\r", "\n").Replace("\n", "\r\n")
Это будет работать, если вход содержит только один тип разрывов строк - либо CR, либо LF, либо CR + LF.
Это зависит от того, что именно. В частности, как вы относитесь к "\ 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();
}
}
string nonNormalized = "\r\n\n\r";
string normalized = nonNormalized.Replace("\r", "\n").Replace("\n", "\r\n");
Простой вариант:
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");
Это быстрый способ сделать это, я имею в виду.
Он не использует дорогостоящую функцию регулярного выражения. Он также не использует несколько функций замены, каждый из которых индивидуально проделывал данные с несколькими проверками, выделениями и т.д.
Таким образом, поиск выполняется непосредственно в 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 в отдельном документе в одном документе.