Нормализовать новые строки в C#

У меня есть поток данных, который может содержать \ 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

Подождите, значит, вы хотите, чтобы \ n \ r соответствовал \ r \ n? Это не нормализация. Ни одна из распространенных платформ не использует \ n \ r в качестве окончания строки.

Derek Park 26.09.2008 22:19

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

ctacke 29.10.2008 06:19
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
28
2
12 300
8
Перейти к ответу Данный вопрос помечен как решенный

Ответы 8

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. Я считаю, что ответ на загадочном языке регулярных выражений, но для меня это черное искусство.

ctacke 26.09.2008 21:56

CQ, это не то, о чем он просил. Регулярное выражение может работать, но не так, как вы его разместили.

Derek Park 26.09.2008 21:56

Согласен, я не учел существующие \ r \ n

Quintin Robinson 26.09.2008 21:57

Вот почему я грубо сказал, что небольшая настройка, такая как предварительная установка \ r \ n, может решить эту проблему.

Quintin Robinson 26.09.2008 21:59

Вы слишком сложно думаете. Игнорируйте каждый \ 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.

Derek Park 26.09.2008 22:05

Хм. Не могу поверить, что он действительно этого хочет :)

VVS 26.09.2008 22:09

Mac использовали CR для переноса строк вплоть до MacOS 9. Это \ n \ r меня удивляет.

Steve Jessop 26.09.2008 22:32

До MacOS X Mac и некоторые 8-битные системы еще в 80-х использовали CR. MacOS X использует LF, как и любая другая система Unix.

Ken Keenan 13.11.2017 12:54
Ответ принят как подходящий

Я считаю, что это сделает то, что вам нужно:

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.

Quintin Robinson 26.09.2008 22:16

Этот близок, но \ n \ r должен просто поменять местами элементы на \ r \ n (видел этот ввод из кода разработчика VB)

ctacke 26.09.2008 22:18

Хорошо, внес это изменение. Я бы не стал рассматривать эту нормализацию, но ее достаточно легко добавить в регулярное выражение.

Derek Park 26.09.2008 22:22

Вам нужно будет удалить "@" из строки замены. Если вы этого не сделаете, он заменит '\ r \ n' на '\\ r \\ n', потому что вы запрашиваете буквальную строку «\ r \ n». Еще лучше было бы заменить на константу Environment.NewLine.

NerdFury 26.09.2008 22:33

Спасибо, что уловили это, NerdFury. Я удалил @ из строки замены. Я бы изменил его на константу NewLine, но поскольку он специально просил "\ r \ n", я полагаю, что я должен оставить это в покое.

Derek Park 26.09.2008 22:42

Что насчет производительности и RegExpr? Возможно, используя Regex Timeout (новое в .net 4.5), RegexMatchTimeoutException и т. д.

Kiquenet 19.06.2013 15:46

Я с Джейми Завински на RegEx:

«Некоторые люди, столкнувшись с проблемой, думают:« Я знаю, я буду использовать регулярные выражения ». Теперь у них две проблемы»

Для тех из нас, кто предпочитает удобочитаемость:

  • Шаг 1

    Заменить \ r \ n на \ n

    Замените \ n \ r на \ n (если вы действительно этого хотите, некоторые плакаты, кажется, думают, что нет)

    Заменить \ r на \ n

  • Шаг 2 Замените \ n на Environment.NewLine или \ r \ n или что-то еще.

Это тривиальное регулярное выражение. Я бы согласился с вами, если бы это был разбор HTML.

cchamberlain 12.08.2015 02:38

Я согласен, что Regex - это ответ, однако все остальные не упоминают разделители строк Unicode. Те (и их варианты с \ n) должны быть включены.

У вас есть решение для этого? Было бы полезно узнать.

Phil 17.01.2017 12:55

Нормализовать перерывы, чтобы все они соответствовали \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 по отдельности в одном документе.

Это копирование массива для изменения его размера может создать много мусора.

CodeCaster 15.05.2018 10:58

Этот код основан на функции Replace конструктора строк. Источник: linksource.microsoft.com/#mscorlib/system/text/… Убедитесь, что емкость также основана на свойстве емкости списка. Источник: linksource.microsoft.com/#mscorlib/system/collections/…

Roberto B 15.05.2018 11:16

Это очень много кода для замены очень простого регулярного выражения. Не уверен, почему вы предполагаете, что регулярное выражение будет «дорогостоящим», случаи, когда регулярное выражение работает медленнее, чем код, который вы бы написали самостоятельно, довольно редки.

mhenry1384 12.07.2018 15:51

Ужасно много кода ... Может, и нет. Вы когда-нибудь смотрели компиляцию регулярных выражений? Вы можете сделать это с помощью Regex.CompileToAssembly (... Читайте: blog.maartenballiauw.be/post/2017/04/24/… Мне кажется, это часто вызываемая функция, и тогда она хороша для повышения производительности.

Roberto B 16.07.2018 15:27

Это двухэтапный процесс. Сначала вы конвертируете все комбинации \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

Другие вопросы по теме