Предисловие
Недавно я обнаружил, что производительность закономерности в JavaScript в некоторых местах несколько отличается от результатов на других языках или инструментах и является относительно альтернативным. Хотя вам почти невозможно написать их, и вы вряд ли можете использовать правила, которые я упомянул ниже, хорошо их понимать.
Примеры кода в этой статье выполняются в среде JavaScript, которая совместима с ES5. То есть производительность в версиях до IE9, версии вокруг FX4 и т. Д., Скорее всего, отличается от того, что я упоминал ниже.
1. Пустой класс персонажа
Класс символов, который не содержит никаких [] называется пустым классом empty char class . Я считаю, что вы никогда не слышали, чтобы другие называли это, потому что на других языках этот метод написания является незаконным, и все документы и учебные пособия не говорят о незаконном синтаксисе. Позвольте мне продемонстрировать, как другие языки или инструменты сообщают об этой ошибке:
$ echo | grep '[]' grep: непревзойденный [или [^$ echo | sed '/[]/' sed: -e Выражение № 1, символ 4: Неподерное адрес Регулярное выражение $ echo | awk '/[]/' awk: cmd. Строка: 1: /[] /awk: cmd. Строка: 1: ^ Неупомянутая regexpawk: cmd. Строка: 1: ошибка: непревзойденный [или [^:/[] // $ echo | perl -ne '/[]/' непревзойденный [в корпорации; Отмечен <-здесь, в m/ [<-здесь]/ at -e line 1. $ echo | Ruby -ne '/[]/' -E: 1: пустой Char -Class:/[]/$ python -c 'import re; re.match ("[]", "")' traceback (последний вызов последним): файл "<string>", строка 1, в <module> файл "e: /python/lib/re.py", Line 137, in match return return _compile (pattermp). "E: /python/lib/re.py", строка 244, в ошибке _compile, v # недействительные экспресс -эксплу В JavaScript пустой класс символов является законным регулярным компонентом, но его эффект «никогда не совпадает», то есть все потерпит неудачу. Это эквивалентно влиянию (empty negative lookahead)(?!) :
JS> "Whate/n" .match (/[]/g) // NULL Class Class, никогда не совпадайте с Nulljs> "wheting/n" .match (/(?!)/g) // Null Oftion Forw
Очевидно, что в JavaScript такие вещи бесполезны.
2. Отрицайте пустой класс символов
Негативные классы персонажей, которые не содержат каких-либо символов, называются негативным пустым классом Char или пустым отрицательным классом Char, потому что это существительное было «само изготовлено» и аналогично пустому классу символов, упомянутому выше. Этот метод написания также является незаконным на других языках:
$ echo | grep '[^]' grep: непревзойденный [или [^$ echo | sed '/[^]/' sed: -e Выражение № 1, символ 5: Неупомянутый адрес Регулярное выражение $ echo | awk '/[^]/' awk: cmd. Строка: 1: /[^] /awk: cmd. Строка: 1: ^ Неупомянутая regexpawk: cmd. Строка: 1: ошибка: непревзойденный [или [^:/[^] // $ echo | perl -ne '/[^]/' непревзойденный [в режиме; Отмечен <-здесь, в m/ [<-здесь ^]/ AT -E LINE 1. $ ECHO | Ruby -Ne '/[^]/' -E: 1: пустой Char -Class:/[^]/$ python -c 'import re; re.match ("[^]", "")' traceback (самый последний вызов последнему): файл "<string>", строка 1, в <module> file "e: /python/lib/re.py", строка 137, в матче return reeptile (pattermp). "E: /python/lib/re.py", строка 244, в ошибке _compile, v # недействительные экспресс -expressionre_constants.error: неожиданный конец регулярного выражения $ В JavaScript отрицание класса NULL символов является законным регулярным компонентом. Его эффект является как противоположность эффекту класса нулевых символов. Он может соответствовать любому персонажу, включая Newline "/n" , то есть он эквивалентен общему [/s/S] и [/w/W] :
js> "whatever/n".match(/[^]/g) //Neizontal character class, match any character ["w", "h", "a", "t", "e", "v", "e", "r", "/n"]js> "whatever/n".match(/[/s/S]/g) //Complementary character class, match any character ["w", "h", "a", "T", "e", "V", "e", "r", "/n"]
Следует отметить, что его нельзя назвать «постоянным соответствием регулярности», потому что у класса персонажа должен быть персонаж, чтобы соответствовать. Если целевая строка пуста или была использована левой регулярностью, матч потерпит неудачу, например:
js> /bcктиканский
Если вы хотите узнать истинные «правила постоянного сопоставления», вы можете проверить статью, которую я перевел раньше: «Пустые» правила
3. []] и [^]]
Это относительно просто, то есть в регулярных выражениях Perl и некоторых других команд Linux, если класс символов [] содержит правый квадратный кронштейн сразу же после []] квадратного кронштейна, правая квадратная кронштейн будет рассматриваться как обычный символ, то есть он может соответствовать только "]". В JavaScript эта регулярность будет распознаваться как пустой класс символов, за которым следует правый квадратный кронштейн, и пустой класс символов ничего не соответствует .[^]] аналогично: в JavaScript он соответствует произвольному символу (отрицательный класс NULL символ), за которым следует правый квадратный кронштейн, такой как "a]","b]" , в то время как на других языках он соответствует любым не] символам.
$ perl -e 'print "]" = ~/[]]/' 1 $ js -e 'print (/[]]/. test ("]"))' false $ perl -e 'print "x" = ~/[^]]/' 1 $ js -e 'print (/[^]/.4. $ Anchor Point
Некоторые новички думают, что $ соответствует персонажу Newline "/n" , что является большой ошибкой. $-это утверждение с нулевой шириной, невозможно соответствовать реальному персонажу, оно может соответствовать только одной позиции. Разница, о которой я хочу поговорить, происходит в не-мульти-линейном режиме: вы можете подумать, что в не-мульти-линии, разве $ не соответствует этой позиции после последнего персонажа? На самом деле это не так просто. На большинстве других языков, если последним символом в целевой строке является символ Newline "/n" , $ также будет соответствовать позиции перед новой линией, то есть соответствует двум позициям на левой и правой сторонах разрыва линии в конце. Многие языки имеют два обозначения /z и /z. Если вы знаете разницу между ними, вы должны понимать, что в других языках (Perl, Python, PHP, Java, C#...) $ в не-мультизинном режиме эквивалентен /Z, в то время как в JavaScript $ в не-мультизированном режиме эквивалентно /Z (это будет только последняя позиция, независимо от того, является ли последний характер новым линейным). Ruby-это особый случай, потому что по умолчанию по умолчанию в многострочный режим. $ в многослойном режиме будет соответствовать позиции перед каждым новым линином, и, конечно, он также будет включать в себя разрыв линии, который может появиться в конце. Книга Ю Шэна «Регулярные рекомендации» также рассказывает об этих пунктах.
$ perl -e 'print "whets/n" = ~ s/$/reply символ/rg' // глобальная замена любого символа // Положение перед разрывом строки заменяется заменяющим символом // Положение после разрыва линии заменяется на печать $ js -e '("что угодно/n". Зайце (/$/g, «Заменить персонаж»).5. Dot Metacharacter "."
В регулярных выражениях в JavaScript Dot Metacharacter ". может соответствовать всем символам, кроме четырех линейных терминаторов ( /r-обратный возврат, /n-line newline, /u2028-line-разделитель, /U2029-параграф-сепаратор), в то время как на других общих языках будет исключена только Line Newline /N.
6. Цитата вперед
Мы все знаем, что в регулярной обратной ссылке есть обратная ссылка, то есть ссылка на номером BackSlash + на строку, которая сочеталась в предыдущей группе захвата. Цель состоит в том, чтобы снова соответствовать или в качестве результата замены (/ становится $). Но есть особый случай, когда, если ссылочная группа захвата не началась (левый кронштейн ограничен), она использует обратную ссылку, что произойдет? Например, обычный /(/2(a)){2}/ , (a) является второй группой захвата, но соответствующий результат его используется с левой стороны. Мы знаем, что регулярные матчи слева направо. Это происхождение ссылки на заголовок в этом разделе. Это не строгая концепция. Итак, теперь вы думаете об этом, что вернет следующий код JavaScript:
js>/(/2 (a)) {2}/. Exec ("aaa") ???Прежде чем ответить на этот вопрос, давайте посмотрим на спектакль на других языках. Точно так же на других языках написание таким образом в основном недействительно:
$ echo aaa | grep '(/2 (a)) {2}' grep: недействительная обратная ссылка $ echo aaa | sed -r '/(/2 (a)) {2}/' sed: -e выражение № 1, символ 12: незаконная обратная ссылка $ echo aaa | awk '/(/2 (a)) {2}/' $ echo aaa | perl -ne 'print/(/2 (a)) {2}/' $ echo aaa | Ruby -ne 'print $ _ = ~/(/2 (a)) {2}/' $ python -c 'import re; print re.match ("(/2 (a)) {2}", "aaa")' нетВ AWK нет ошибки, потому что AWK не поддерживает эту обратную ссылку, и /2 интерпретируется как символ с кодом ASCII 2. Однако в Perl Ruby Python нет ошибки. Я не знаю, почему этот дизайн должен быть изучен Perl, но эффекты одинаковы. В этом случае невозможно успешно соответствовать.
В JavaScript не только он не сообщает об ошибке, но и может также успешно соответствовать ее. Посмотрим, что ответ такой же, как и тот, который вы только что подумали:
JS> /(/2(a))_200/.exec("aaa") "aaa "," a "," a "] Чтобы вы не забыли, что результат возвращается методом exec , позвольте мне сказать. Первым элементом является полная соответствующая строка, то есть RegExp["$&"] , за которым следует содержание каждого сопоставления группы захвата, то есть RegExp.$1 и RegExp.$2. Почему совпадение может быть успешным? Какой процесс сопоставления? Я понимаю:
Во-первых, мы входим в первую группу захвата (самый левый левый кронштейн), где первый действительный матч составляет /2, но в настоящее время вторая группа захвата (A) еще undefined была на раунде, поэтому значение RegExp.$2 Дело в том, что матч успешен. Продолжайте идти, а затем вторая группа захвата (A) соответствует первой A в целевой строке, а значение RegExp.$2 также назначено «A», а затем первая группа захвата заканчивается (самый правый самый правый самый правый левый кронштейн), значение RegExp.$1 также является «A». Затем есть квантификатор {2}, то есть после первого A в целевой строке, начинается новый раунд сопоставления обычного (/2(a)) . Ключевой момент здесь: значение RegExp.$2 состоит в том, что значение /2 соответствует или это значение, назначенное в конце первого раунда соответствия «a». Ответ: «Нет», значения RegExp.$1 и RegExp.$2 будут очищены как undefined , а /1 и /2 будут такими же, как первый раз, успешно сопоставляя пустой символ (эквивалентный без эффекта, независимо от того, написано или нет). Второй A в целевой строке успешно соответствует, а значения RegExp.$1 и RegExp.$2 становятся «A» снова, значение RegExp["$&"] становится полной соответствующей строкой, первыми двумя a: "aa".
В более ранних версиях Firefox (3.6) повторный матч квантификаторов не очистит значение существующей захваченной группы, так что во втором раунде матчей /2 будет соответствовать второму A, таким образом::
js> /(/2(a) aexec("aaa"")on"aaa "," a "]Кроме того, конец группы захвата зависит от того, закрыт ли закрывающий кронштейн. Например,/(a/1) {3}/. Хотя первая группа захвата начала соответствовать, когда используется /1, она еще не закончилась. Это также прямая ссылка, поэтому совпадение между /1 все еще пусто:
JS> /(A/1) <300/.exec("aaa") "aaaa "," a "]Другой пример:
JS> /(?:(f)(o)(o)(b)(a)(r))*/.
* это квантификатор. После первого раунда соответствия: 1 доллар - «F», 2 доллара - это «O», 3 доллара - «O», 4 доллара не определен, 5 долларов undefined , а 6 долларов undefined .
В начале второго раунда матчей: все захваченные значения сбрасываются в undefined .
После второго раунда матчей: 1 доллар undefined , 2 доллара undefined , 3 доллара undefined , 4 доллара - «B», 5 долларов - «а», а 6 долларов - «r».
и назначен как «Foobar», а совпадение заканчивается.
Суммировать
Вышеуказанное - весь контент, который суммирует различия между регулярностью JavaScript и другими языками. Я надеюсь, что содержание этой статьи будет полезно для каждого обучения и работы.