Почему не работает "жадный" режим RegExp?
Я не понимаю поведение. У меня есть такой пример, нужно ловить html комментарий.
var str = '.. <!--My -- comment test--> ';
var regex1 = /<!--[.]*-->/g;
var regex2 = /<!--.*-->/g;
alert(str.match(regex1)); // null
alert(str.match(regex2)); // <!--My -- comment test-->
Второе регулярное выражение regex2
работает отлично, выводит именно то что нужно. Первые шоу null
, И я не понимаю разницу. RegExpressions <!--[.]*-->
а также <!--.*-->
значит то же самое - "после <!--
возьмите ЛЮБОЙ символ кроме символа новой строки в количестве от 0 до как можно большего количества и завершите -->
". Но для второго это работает, а для первого нет. Почему?
UPD. Я прочитал комментарии и получил обновление.
var str3 = '.. <!--Mycommenttest--> ';
var str4 = '.. <!--My comment test--> ';
var regex3 = /<!--[\w]*-->/g;
var regex4 = /<!--[\s\S]*-->/g;
alert(str.match(regex3)); // <!--Mycommentstest-->
alert(str.match(regex4)); // <!-- My comment test -->
Таким образом, можно использовать ограниченные совпадающие переменные для сопоставления чего угодно. Так какой путь следует использовать для правильного использования RegExps? С []
или без них? Не могу получить разницу, оба дают правильный вывод.
4 ответа
Сокращения класса персонажа, такие как \w
, \d
а также \s
означают точно такие же внутри классов символов, как и вне, но метасимволы, как .
обычно теряют свое особое значение внутри классов персонажей. Вот почему /<!--[.]*-->/
не работает, как вы ожидали: [.]
соответствует буквальному .
,
Но /<!--.*-->/
на самом деле тоже не работает, так как .
не соответствует переводу строки. В большинстве разновидностей регулярных выражений вы используете однострочный режим, чтобы точка соответствовала всем символам, включая символы новой строки, например: /<!--.*-->/s
или это: (?s)<!--.*-->
, Но JavaScript не поддерживает эту функцию, поэтому большинство людей используют [\s\S]
вместо этого означает "любой символ пробела или любой символ, который не является пробелом"- другими словами, любой символ.
Но это тоже неправильно, поскольку (как отметил Джейсон в своем комментарии) он будет жадно соответствовать всему с первого раза. <!--
до конца -->
, который может включать несколько отдельных комментариев и все некомментированные материалы между ними. Чтобы сделать это действительно правильно, вероятно, не стоит усилий. При использовании регулярных выражений для соответствия HTML, вы все равно должны сделать много упрощающих предположений; если вы не можете принять определенный уровень правильной формы, вы можете сдаться. В этом случае должно быть достаточно сделать квантификатор не жадным:
var regex5 = /<!--[\s\S]*?-->/g;
Точка (.
) не означает "что-нибудь" внутри класса символов. Зачем вам нужен класс персонажей, чтобы соответствовать чему-либо?
RegExpressions
<!--[.]*-->
а также<!--.*-->
значит то же самое
Это не правильно.
Скобки []
указать класс символов, где любой символ в классе может быть сопоставлен. [.]
это класс символов, который содержит.
' персонаж. Сравните это с .
, который является предопределенным символьным классом, принятым для обозначения "любой символ" (кроме ограничителей строки).
Так что вы соответствуете <!--[.]*-->
это либо пустой комментарий, либо комментарий, состоящий полностью из '.
' персонажи. И с чем вы подходите <!--.*-->
это либо пустой комментарий, либо комментарий, заполненный любым символом, кроме переносов строк.
Первое не потому, что это не значит то же самое. Первый означает совпадение символа периода. Символ точки не является общим совпадением, если помещен в набор []. (и если вы подумаете об этом, это имеет смысл: почему вы хотите сопоставить что-либо внутри набора ограниченных совпадающих переменных)