Соответствие переносам строк - \n или \r\n?

Во время написания этого ответа мне приходилось сопоставлять исключительно переводы строк вместо использования s -флаг (dotall - точка соответствует переводу строки).

Сайты, обычно используемые для проверки регулярных выражений, ведут себя по-разному при попытке сопоставления на \n или же \r\n,

Я заметил

  • Regex101 соответствует разрывам строк только на \n
    ( пример - удалить \r и это совпадает)

  • RegExr не соответствует разрывам строк ни на \n ни на \r\n
    и я не могу найти что-то, чтобы это соответствовало разрыву строки, кроме m -флаг и \s
    ( пример)

  • Debuggex ведет себя еще более по-разному:
    в этом примере это соответствует только на \r\n, в то время как
    здесь это только соответствует \n с такими же флагами и указанным двигателем

Я полностью осведомлен о m-флаг (многострочный - делает ^ соответствовать началу и $ конец строки), но иногда это не вариант. То же самое с \s, так как он совпадает с табуляцией и пробелами тоже.

Моя мысль использовать символ перевода строки Unicode (\u0085) не удалось, так что:

  1. Есть ли надежный способ интегрировать совпадение на разрыв строки (желательно независимо от используемого языка) в регулярное выражение?
  2. Почему вышеупомянутые сайты ведут себя по-разному (особенно Debuggex, сопоставляя только один раз на \n и только один раз на \r\n)?

7 ответов

Решение

Собираюсь ответить в обратном направлении;)

2) Для полного объяснения \ r и \ n я должен обратиться к этому вопросу, который является гораздо более полным, чем я опубликую здесь: Разница между \ n и \r?

Короче говоря, Linux использует \ n для новой строки, Windows \r\n и старых Macs \r. Так что есть несколько способов написать новую строку. Ваш второй инструмент (RegExr), например, сопоставляет одиночный \ r.

1) [\r\n]+ как предположил Илья, будет работать, но также будет соответствовать нескольким последовательным новым строкам. (\r\n|\r|\n) правильнее

В блокноте ++ \R совпадает как с \n, так и с \r\n.

У вас есть разные окончания строк в текстах примеров в Debuggex. Что особенно интересно, так это то, что Debuggex определил, какой стиль окончания строки вы использовали первым, и он преобразует все дополнительные окончания строки, введенные в этот стиль.

Я использовал Notepad++ для вставки образца текста в формате Unix и Windows в Debuggex, и что бы я ни вставил первым, это то, с чем застрял этот сеанс Debuggex.

Итак, вы должны вымыть свой текст через текстовый редактор, прежде чем вставлять его в Debuggex. Убедитесь, что вы вставляете стиль, который хотите. По умолчанию в Debuggex используется стиль Unix (\n).

Кроме того, NEL (\u0085) - это нечто совершенно иное: https://en.wikipedia.org/wiki/Newline

(\r?\n) будет охватывать Unix и Windows. Вам нужно что-то более сложное, как (\r\n|\r|\n), если вы хотите соответствовать старому Mac тоже.

Не уверен, что это то, о чем просили:

      (somethingToStaMatch)(.|\n)*?(somethingToEndMatch)

Это будет иметь 3 группы матчей. И ALLWITHLINEBREAKS посередине. Может помочь кому-то протестированному с dotnet.

строковый шаблон = @"(somethingToStartMatch)(.|\n)*?(somethingToEndMatch)";

Обратите внимание, что *?позволяет сопоставлять, даже если ваш текст имеет несколько пар ключевых слов!

В Python:

# as Peter van der Wal's answer
re.split(r'\r\n|\r|\n', text, flags=re.M) 

или более строгое:

# https://docs.python.org/3/library/stdtypes.html#str.splitlines
str.splitlines()

Это относится только к вопросу 1.

У меня есть приложение, которое работает в Windows и использует многострочный редактор MFC.
В окне редактора ожидаются разрывы строк CRLF, но мне нужно разобрать введенный текст
с некоторыми действительно большими / противными регулярными выражениями.

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

Это не займет много времени.
Это то, что я использую.

 boost::regex  CRLFCRtoLF (
     " \\r\\n | \\r(?!\\n) "
     , MODx);

 boost::regex  CRLFCRtoCRLF (
     " \\r\\n?+ | \\n "
     , MODx);


 // Convert (All style) linebreaks to linefeeds 
 // ---------------------------------------
 void ReplaceCRLFCRtoLF( string& strSrc, string& strDest )
 {
    strDest  = boost::regex_replace ( strSrc, CRLFCRtoLF, "\\n" );
 }

 // Convert linefeeds to linebreaks (Windows) 
 // ---------------------------------------
 void ReplaceCRLFCRtoCRLF( string& strSrc, string& strDest )
 {
    strDest  = boost::regex_replace ( strSrc, CRLFCRtoCRLF, "\\r\\n" );
 }

Немного опоздал на вечеринку, но в остальном может быть, возможно, полезен. В javascript вы можете просто написать канал ( |), чтобы соответствовать символам новой строки/разрыву строки. В моем случае мне нужно было избавиться от всех запятых, точек с запятой и пробелов (включая разрывы строк), поэтому в итоге я использовал это:

.split(/[\s,;|]+/)

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