У меня есть поток данных, который может содержать \ r, \ n, \ r \ n, \ n \ r или любую их комбинацию. Есть ли простой способ нормализовать данные, чтобы все они просто превратились в пары \ r \ n, чтобы сделать отображение более согласованным?
Итак, что-то, что дало бы такую таблицу перевода:
\r --> \r\n
\n --> \r\n
\n\n --> \r\n\r\n
\n\r --> \r\n
\r\n --> \r\n
\r\n\n --> \r\n\r\n
Разве я не сказал, что это нормальная платформа, не так ли? Я видел данные (в частности, из кода VB), в котором это так, и мне нужно это учитывать. Извините, если это не соответствует строгому определению «нормализации», но определенно соответствует определению данных, которые мне нужно обработать, в чем суть





Regex может помочь ... может сделать что-то вроде этого ...
(\ r \ n | \ n \ n | \ n \ r | \ r | \ n) заменить на \ r \ n
Это регулярное выражение произвело эти результаты из опубликованной таблицы (просто тестировало левую часть), поэтому замена должна нормализоваться.
\r => \r
\n => \n
\n\n => \n\n
\n\r => \n\r
\r\n => \r\n
\r\n => \r\n
\n => \n
За исключением случаев, когда он уже содержит \ r \ n, замена расширит его до \ r \ n \ r \ n. То же самое для \ n \ r. Я считаю, что ответ на загадочном языке регулярных выражений, но для меня это черное искусство.
CQ, это не то, о чем он просил. Регулярное выражение может работать, но не так, как вы его разместили.
Согласен, я не учел существующие \ r \ n
Вот почему я грубо сказал, что небольшая настройка, такая как предварительная установка \ r \ n, может решить эту проблему.
Вы слишком сложно думаете. Игнорируйте каждый \ r и превращайте каждый \ n в \ r \ n.
В псевдо-C#:
char[] chunk = new char[X];
StringBuffer output = new StringBuffer();
buffer.Read(chunk);
foreach (char c in chunk)
{
switch (c)
{
case '\r' : break; // ignore
case '\n' : output.Append("\r\n");
default : output.Append(c);
}
}
РЕДАКТИРОВАТЬ: \ r сам по себе не является ограничителем строки, поэтому я сомневаюсь, что вы действительно хотите расширить \ r до \ r \ n.
Он хочет, чтобы автономный \ r тоже превратился в \ r \ n.
Хм. Не могу поверить, что он действительно этого хочет :)
Mac использовали CR для переноса строк вплоть до MacOS 9. Это \ n \ r меня удивляет.
До MacOS X Mac и некоторые 8-битные системы еще в 80-х использовали CR. MacOS X использует LF, как и любая другая система Unix.
Я считаю, что это сделает то, что вам нужно:
using System.Text.RegularExpressions;
// ...
string normalized = Regex.Replace(originalString, @"\r\n|\n\r|\n|\r", "\r\n");
Я не уверен на 100% в точном синтаксисе, и у меня нет компилятора .Net, который можно было бы проверить. Я написал его на perl и преобразовал в (надеюсь, правильный) C#. Единственный реальный трюк - сначала сопоставить "\ r \ n" и "\ n \ r".
Чтобы применить его ко всему потоку, просто обработайте фрагменты ввода. (Вы можете сделать это с помощью обертки потока, если хотите.)
Исходный perl:
$str =~ s/\r\n|\n\r|\n|\r/\r\n/g;
Результаты тестирования:
[bash$] ./test.pl
\r -> \r\n
\n -> \r\n
\n\n -> \r\n\r\n
\n\r -> \r\n
\r\n -> \r\n
\r\n\n -> \r\n\r\n
Обновление: теперь преобразует \ n \ r в \ r \ n, хотя я бы не стал называть это нормализацией.
Это не соответствовало требованиям приведенного выше примера в таблице. Посмотрите на измененное мной регулярное выражение, вам нужно учитывать \ n \ n.
Этот близок, но \ n \ r должен просто поменять местами элементы на \ r \ n (видел этот ввод из кода разработчика VB)
Хорошо, внес это изменение. Я бы не стал рассматривать эту нормализацию, но ее достаточно легко добавить в регулярное выражение.
Вам нужно будет удалить "@" из строки замены. Если вы этого не сделаете, он заменит '\ r \ n' на '\\ r \\ n', потому что вы запрашиваете буквальную строку «\ r \ n». Еще лучше было бы заменить на константу Environment.NewLine.
Спасибо, что уловили это, NerdFury. Я удалил @ из строки замены. Я бы изменил его на константу NewLine, но поскольку он специально просил "\ r \ n", я полагаю, что я должен оставить это в покое.
Что насчет производительности и RegExpr? Возможно, используя Regex Timeout (новое в .net 4.5), RegexMatchTimeoutException и т. д.
Я с Джейми Завински на RegEx:
«Некоторые люди, столкнувшись с проблемой, думают:« Я знаю, я буду использовать регулярные выражения ». Теперь у них две проблемы»
Для тех из нас, кто предпочитает удобочитаемость:
Шаг 1
Заменить \ r \ n на \ n
Замените \ n \ r на \ n (если вы действительно этого хотите, некоторые плакаты, кажется, думают, что нет)
Заменить \ r на \ n
Шаг 2 Замените \ n на Environment.NewLine или \ r \ n или что-то еще.
Это тривиальное регулярное выражение. Я бы согласился с вами, если бы это был разбор HTML.
Я согласен, что Regex - это ответ, однако все остальные не упоминают разделители строк Unicode. Те (и их варианты с \ n) должны быть включены.
У вас есть решение для этого? Было бы полезно узнать.
Нормализовать перерывы, чтобы все они соответствовали \r\n.
var normalisedString =
sourceString
.Replace("\r\n", "\n")
.Replace("\n\r", "\n")
.Replace("\r", "\n")
.Replace("\n", "\r\n");
Это ответ на вопрос. Данное решение заменяет строку заданной таблицей перевода. Он не использует дорогостоящую функцию регулярного выражения. Он также не использует несколько функций замены, каждая из которых по отдельности перебирала данные с несколькими проверками и т. д.
Таким образом, поиск выполняется непосредственно в цикле 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 по отдельности в одном документе.
Это копирование массива для изменения его размера может создать много мусора.
Этот код основан на функции Replace конструктора строк. Источник: linksource.microsoft.com/#mscorlib/system/text/… Убедитесь, что емкость также основана на свойстве емкости списка. Источник: linksource.microsoft.com/#mscorlib/system/collections/…
Это очень много кода для замены очень простого регулярного выражения. Не уверен, почему вы предполагаете, что регулярное выражение будет «дорогостоящим», случаи, когда регулярное выражение работает медленнее, чем код, который вы бы написали самостоятельно, довольно редки.
Ужасно много кода ... Может, и нет. Вы когда-нибудь смотрели компиляцию регулярных выражений? Вы можете сделать это с помощью Regex.CompileToAssembly (... Читайте: blog.maartenballiauw.be/post/2017/04/24/… Мне кажется, это часто вызываемая функция, и тогда она хороша для повышения производительности.
Это двухэтапный процесс.
Сначала вы конвертируете все комбинации \r и \n в одну, скажем, \r
.
Затем вы конвертируете весь \r в ваш целевой \r\n.
normalized =
original.Replace("\r\n", "\r").
Replace("\n\r", "\r").
Replace("\n", "\r").
Replace("\r", "\r\n"); // last step
Подождите, значит, вы хотите, чтобы \ n \ r соответствовал \ r \ n? Это не нормализация. Ни одна из распространенных платформ не использует \ n \ r в качестве окончания строки.