Як використовувати регулярний вираз 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
Менш криптований виразка? Неможливо, від природи.
Рубенс Фаріас

btw, вам слід прочитати: "Розбір Html: шлях Ктулху" codinghorror.com/blog/archives/001311.html
Rubens Farias

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, хоча синтаксиси wiki, змішані з HTML, можуть мати самі різні кутові випадки.
Брайан Кемпбелл

2
[\r\n]застосовано до послідовності \ r \ n, спочатку відповідатиме \ r, а потім \ n. Якщо ви хочете одразу співставити всю послідовність, незалежно від того, чи є ця послідовність \ r \ n чи просто \ n, використовуйте шаблон.|\r?\n
Ерік Біркеланд

1
Щоб відповідати цілій рядковій рядку, спробуйте жадібну [\s\S]+.
Боаз

Я просто хочу додати для нащадків, що синтаксис JS regex, що ігнорує значення .всередині [], відрізняється від інших фреймворків регулярних виразів, особливо просунутого в .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 для документації зі спеціальними символами на regexp.
KrisWebDev

4
Будь-яка причина віддати перевагу [\s\S]перед іншими, на кшталт [\d\D]чи [\w\W]?
Фрогз

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]не працює, тому що крапка в [](за визначенням regex; не тільки 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.