Как использовать регулярные выражения JavaScript на нескольких строках?


275
var ss= "<pre>aaaa\nbbb\nccc</pre>ddd";
var arr= ss.match( /<pre.*?<\/pre>/gm );
alert(arr);     // null

Я бы хотел, чтобы был поднят блок PRE, даже если он охватывает символы новой строки. Я думал, что флаг «м» делает это. Не.

Нашел ответ здесь перед публикацией. Так как я думал, что знаю JavaScript (прочитал три книги, работал часами), и в SO не было никакого решения, я все же осмелюсь опубликовать. бросать камни сюда

Итак, решение таково:

var ss= "<pre>aaaa\nbbb\nccc</pre>ddd";
var arr= ss.match( /<pre[\s\S]*?<\/pre>/gm );
alert(arr);     // <pre>...</pre> :)

У кого-нибудь есть менее загадочный способ?

Изменить: это дубликат, но так как его сложнее найти, чем я, я не удаляю.

Это предлагается [^]как "многострочная точка". Что я до сих пор не понимаю, так это почему [.\n]не работает. Думаю, это одна из печальных частей JavaScript.


29
Менее загадочное регулярное выражение? Невозможно по природе.
Рубенс Фариас

Кстати, вы должны прочитать: «Разбор HTML: Путь Ктулху» codinghorror.com/blog/archives/001311.html
Фариас Рубенса

1
Ссылка изменилась по сравнению с предыдущим комментарием: blog.codinghorror.com/parsing-html-the-cthulhu-way (5yrs-иш позже)
мазок

Ответы:


248

[.\n]не работает, потому что .не имеет особого значения внутри [], это просто означает буквальный .. (.|\n)будет способ указать «любой символ, включая перевод строки». Если вы хотите , чтобы соответствовать всем новым строкам, вам нужно будет добавить , \rа также включить Окна и классического Mac OS стиль завершение строк: (.|[\r\n]).

Это оказывается несколько громоздким, а также медленным (см. Подробности в ответе KrisWebDev ), поэтому лучшим подходом было бы сопоставить все пробельные символы и все непробельные символы с [\s\S], что будет соответствовать всему, быстрее и проще.

В общем, вы не должны пытаться использовать регулярное выражение для соответствия фактическим тегам HTML. См., Например, эти вопросы для получения дополнительной информации о том, почему.

Вместо этого попробуйте на самом деле найти в DOM нужный вам тег (использование jQuery делает это проще, но вы всегда можете сделать это document.getElementsByTagName("pre")со стандартным DOM), а затем выполнить поиск текстового содержимого этих результатов с помощью регулярного выражения, если вам нужно сопоставить его с содержимым. ,


Я делаю .wiki -> конвертацию HTML на лету, используя JavaScript. Поэтому у меня пока нет доступной DOM. Файл Wiki в основном имеет собственный синтаксис, но я разрешаю использовать теги HTML, если это необходимо. Ваш совет очень действителен, если бы я имел дело с DOM с этим. Спасибо. :)
akauppi

Справедливо. Я полагаю, что это является веской причиной для того, чтобы использовать регулярные выражения в HTML, хотя синтаксисы вики, смешанные с HTML, могут иметь все виды забавных угловых случаев сами.
Брайан Кэмпбелл

2
[\r\n]применяется к последовательности \ r \ n, сначала будет соответствовать \ r, а затем \ n. Если вы хотите сопоставить всю последовательность сразу, независимо от того, является ли эта последовательность \ r \ n или просто \ n, используйте шаблон.|\r?\n
Eirik Birkeland

1
Чтобы сопоставить всю многострочную строку, попробуйте жадный [\s\S]+.
Вооз

Я просто хочу добавить для потомков, что синтаксис регулярных выражений JS, игнорирующий значение .внутри [], отличается от других сред регулярных выражений, в частности от продвинутого в .NET. Люди, пожалуйста, не думайте, что регулярные выражения являются кросс-платформенными, а зачастую и нет !!
г-н ТА

330

НЕ использовать (.|[\r\n])вместо .многострочного сопоставления.

DO использовать [\s\S]вместо .для многострочного согласования

Кроме того, избегайте жадности там, где это не нужно, используя *?или +?квантификатор вместо *или +. Это может оказать огромное влияние на производительность.

Посмотрите тест, который я сделал: http://jsperf.com/javascript-multiline-regexp-workarounds

Using [^]: fastest
Using [\s\S]: 0.83% slower
Using (.|\r|\n): 96% slower
Using (.|[\r\n]): 96% slower

NB: Вы также можете использовать, [^]но это не рекомендуется в комментариях ниже.


22
Хорошие моменты, но я рекомендую против использования в [^]любом случае. С одной стороны, JavaScript - единственный известный мне вариант, который поддерживает эту идиому, и даже там он используется далеко не так часто, как [\s\S]. С другой стороны, большинство других вкусов позволяют вам избежать ], перечислив его первым. Другими словами, в JavaScript [^][^]соответствует любым двум символам, но в .NET он соответствует любому один символ , отличный ], [или ^.
Алан Мур

1
Как вы знаете, что \Sбудет соответствовать \rили \nпротив какого-либо другого персонажа?
Гили

3
Смотрите этот вопрос для деталей \ s \ S. Это хак для соответствия всем символам пробела + всем непробельным символам = всем символам. Смотрите также MDN для документации специальных символов регулярных выражений.
KrisWebDev

4
Любая причина, чтобы предпочесть [\s\S]другим, как [\d\D]или [\w\W]?
Phrogz

1
Позвольте мне быстро указать, что ваш тест для жадного оператора сфальсифицирован. /<p>Can[^]*?<\/p>/не соответствует тому же контенту, что и /<p>Can[^]*<\/p>/. Жадный вариант должен быть изменен, /<p>(?:[^<]|<(?!\/p>))*<\/p>/чтобы соответствовать тому же содержанию.
3limin4t0r

19

Вы не указываете свою среду и версию Javascript (ECMAscript), и я понимаю, что этот пост был за 2009 год, но только для полноты, с выпуском ECMA2018 теперь мы можем использовать sфлаг, чтобы вызвать .совпадение с \ n, см. Https : //stackoverflow.com/a/36006948/141801

Таким образом:

let s = 'I am a string\nover several\nlines.';
console.log('String: "' + s + '".');

let r = /string.*several.*lines/s; // Note 's' modifier
console.log('Match? ' + r.test(s); // 'test' returns true

Это недавнее добавление, которое не будет работать во многих современных средах, например, Node v8.7.0, похоже, не распознает его, но работает в Chromium, и я использую его в тесте Typescript, который я пишу, и предположительно это со временем станет более популярным.


1
Это прекрасно работает в Chrome (v67), но полностью нарушает регулярное выражение (также перестает работать построчно) в IE11 и IEdge (v42)
freedomn-m

Спасибо @ freedomn-m .. IE, не поддерживающий очень новую функцию, почти не удивляет :) Но да, стоит упомянуть, где это не работает, чтобы спасти кого-либо, пытающегося «отладить», почему их попытка использовать его не работает как и ожидалось.
Neek

11

[.\n]не работает, потому что точка в [](по определению регулярного выражения; не только в javascript) означает символ точки. Вы можете использовать (.|\n)(или (.|[\n\r])) вместо этого.


24
[\s\S]является наиболее распространенной идиомой JavaScript для сопоставления всего, включая переводы строк. Это проще для глаз и намного эффективнее, чем подход, основанный на чередовании (.|\n). (Это буквально означает «любой символ, который является пробелом или любой символ, который не является пробелом.)
Алан Мур

2
Вы правы, но вопрос был о .и \n, и почему [.\n]не работает. Как уже упоминалось в вопросе, [^]это также хороший подход.
Й. Шохам

6

Я проверил его (Chrome), и он работает для меня (как [^]и [^\0]), изменяя точку ( .) либо на, [^\0]либо [^], потому что точка не соответствует разрыву строки (см. Здесь:http://www.regular-expressions.info/dot.html ).

var ss= "<pre>aaaa\nbbb\nccc</pre>ddd";
var arr= ss.match( /<pre[^\0]*?<\/pre>/gm );
alert(arr);     //Working


1
Проблема в [^\0]том, что он не будет соответствовать нулевым символам, даже если в строках Javascript разрешены нулевые символы (см. Этот ответ ).
Дональд Дак

0

Помимо вышеприведенных примеров, это альтернатива.

^[\\w\\s]*$

Где \wдля слов и \sдля пробелов

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.