Почему / [\ w - +] / правильное регулярное выражение, но / [\ w - +] / u недействительно? - PullRequest
0 голосов
/ 15 января 2019

Если я наберу /[\w-+]/ в консоли Chrome, он его примет. Я получаю объект регулярного выражения, который я могу использовать для проверки строк как обычно. Но если я наберу /[\w-+]/u, будет написано VM112:1 Uncaught SyntaxError: Invalid regular expression: /[\w-+]/: Invalid character class.

В Firefox /[\w-+]/ работает нормально, но если я наберу /[\w-+]/u в консоли, он просто перейдет к следующей строке, как будто я набрал неполное утверждение. Если я попытаюсь заставить его создать регулярное выражение, запустив eval('/[\w-+]/u'), он скажет мне SyntaxError: invalid range in character class.

Почему флаг u делает регулярное выражение недействительным? Документация MDN RegExp говорит, что u включает некоторые функции Unicode, но я ничего не вижу о том, как это влияет на диапазоны в классах символов.

Ответы [ 2 ]

0 голосов
/ 16 января 2019

Для этого есть отчет: Реализация V8: поведение свойства юникода в диапазоне классов символов преднамеренно отличается от других классов? .


Я взглянул на исходный код V8 ( regexp-parser.cc ) и нашел это:

if (is_class_1 || is_class_2) {
    // Either end is an escaped character class. Treat the '-' verbatim.
    if (unicode()) {
       // ES2015 21.2.2.15.1 step 1.
       return ReportError(CStrVector(kRangeInvalid));
    }

kRangeInvalid - это константа, которая содержит Invalid character class.

21.2.2.15.1 шаг 1.

Если A не содержит ровно один символ или B не содержит ровно один символ, выведите SyntaxError исключение.

0 голосов
/ 15 января 2019

В наборе RegExp символ дефис-минус (ваша стандартная клавиатура) обозначает диапазон кодов символов между двумя символами, которые он разделяет. Исключения составляют случаи, когда он экранирован (\-) или когда он не разделяет два символа, поскольку он является либо последним символом класса, либо первым символом (после дополнительной каретки, которая инвертирует класс).

Три примера диапазонов символов: простой пример, расширенный пример и ошибка:

  • [a-z] довольно просто, потому что работает так, как мы ожидаем, хотя на самом деле это происходит потому, что коды символов оказываются последовательными. Другой способ написать это [\x61-\x7a]
  • [!-~] не совсем прост, по крайней мере, пока вы не посмотрите на карту символов и не узнаете, что ! - это первый печатный символ ASCII, а ~ - последний (из «нижнего ASCII»), поэтому это способ сказать "все печатаемые нижние символы ASCII", и это эквивалент [\x21-\x7e]
  • [A-z] имеет переключаемый корпус. Вам может не понравиться тот факт, что в этом диапазоне допустимо шесть не буквенных символов (то есть [\x41-\x7a])

ASCII Table


Теперь давайте проверим ваше регулярное выражение /[\w-+]/u Regex101 имеет более информативную ошибку: «Вы не можете создать диапазон с краткими escape-последовательностями»

Так как \w сам по себе не является символом (а скорее набором символов), примыкающая черточка должна восприниматься буквально или же как ошибка. Когда вы вызываете его с флагом /u для запуска fullUnicode, вы входите в более строгий режим и, следовательно, получаете ошибку.

Ошибка, которую я получаю от "foo".match(/[\w-+]/u) в Firefox 64.0:

SyntaxError: символьный escape нельзя использовать в диапазоне классов в регулярном выражении

Это немного более информативно, чем ошибка, которую вы получили, поскольку она фактически говорит вам, что проблема в побеге (хотя и не в том, почему это проблема).

Согласно ECMAScript 2015's RegExBuiltinExec() логика :

  1. Если fullUnicode равен true , то
    1. e - это индекс в списке символов Input , полученный из S , которому соответствует matcher . Пусть eUTF будет наименьшим индексом в S , который соответствует символу в элементе e из Input . Если e больше или равно длине Input , тогда eUTF - это количество единиц кода в S.
    2. Пусть e будет eUTF .

Кажется, это явно строит свою собственную логику разбора диапазона.


Решение состоит в том, чтобы либо убежать от вашего дефис-минуса, либо поставить его последним (или первым):

/[\w\-+]/u или /[\w+-]/u или /[-\w+]/u. Лично я всегда ставлю это последним.

...