Подтвердить что ты не робот

Почему утверждения lookbehind не поддерживаются в Javascript?

Недавно я понял (с некоторым смущением), что регулярное выражение lookbehind assertions не было возможным в Javascript.

Какова (фактическая) причина отсутствия для этого утверждения так кажутся обычным?

Я понимаю, что есть альтернативные способы достижения того же самого, возможно,, хотя это основная семантика на работе, которая запрещает функциональность или что именно?

Также кажется, что некоторые инструменты тестирования регулярных выражений, которые генерируют Javascript-код из шаблонов регулярных выражений, похоже, игнорируют этот факт - который поражает меня как бит нечетный.

4b9b3361

Ответ 1

Похоже, в то время Брендан Эйч не знал о его существовании (поскольку Netscape был построен на более старой версии Perl ):

Это было в 1998 году, работа Netscape 4, которую я сделал в 97 году, была основана на Perl 4 (!), но мы предложили ECMA TC39 TG1 (группа JS - все было иначе, включая капитализацию), что-то основано на Perl 5 Мы не получили все, и нам пришлось рационализировать некоторые очевидные причуды.

Я не помню, как lookbehind (появившийся в Perl 5.005 в июле 1998 года) был специально выделен. Вальдемар может вспомнить больше, я передал ему ключи JS внутри netscape.com, чтобы пойти на mozilla.org.

Если вы играете для написания предложения или мини-спецификации (в стиле ES5 даже), дайте мне знать. На следующей неделе я общаюсь с другими TC39'ерами.

/будет

В списке рассылки было множество разных элементов с попытками включить его, но все же кажется, что это довольно сложная функция, потому что Регулярные выражения EcmaScript - это backtracking, основанный на возврате и обратном отслеживании, необходим в поиске при работе с группами захвата. Это может привести к таким проблемам, как катастрофическое обратное отслеживание при неправильном использовании.

В какой-то момент это было предложено для ES6/Es 2015, но оно никогда не делало проект, не говоря уже о спецификации. В последний пост в обсуждении кажется, что никто не взял на себя задачу его реализации. Если кто-то чувствует себя призванным для написания реализации, они могут зарегистрироваться для ES Обсудить список и предложить его.

Обновление до 2015 года:

В мае 2015 года Nozomu Katō предложил реализацию внешнего вида ES7.

Обновление сентябрь 2015 года:

Regex Look-behind был добавлен как этап 0.

Обновление до 2017 года:

Предложение находится на этапе 3. Это означает, что теперь по крайней мере два браузера должны реализовать его, чтобы он стал частью следующего стандарта EcmaScript. Как отметил @martixy в комментариях, Chrome реализовал его за экспериментальным флагом JS.

Ответ 2

Если говорить о заключении, я думаю, что внешний вид JavaScript не реализован в JavaScript, поскольку никто не знает, как он должен вести себя, а существующие реализации показывают, что добавление поддержки look-behind довольно сложный.

JavaScript/ECMAScript отличается от других языков в том смысле, что спецификация включает абстрактную реализацию механизма regex, в то время как большинство других языков только останавливается при описании поведения каждой части синтаксиса регулярного выражения, с небольшим описанием того, как разные токены взаимодействуют друг с другом.

упреждающая? Легко реализовать

Реализация взгляда довольно проста. Вам нужно только обработать шаблон внутри внешнего вида таким же образом, как и внешний внешний вид, и выполнить совпадение слева направо в соответствии с обычным, за исключением того, что после успешного выполнения поиска 1) текущая позиция восстанавливается до входа в режим ожидания, а 2) точки выбора внутри look-ahead отбрасываются после согласования.

Нет ограничений на то, что может быть включено внутри look-ahead, так как это очень простое расширение существующих естественных объектов соответствия слева направо.

Посмотрите-за? Не так просто

С другой стороны, реализация look-behind не так прямолинейна.

Представьте, как реализовать следующую конструкцию:

(?<=fixed-string)
(?<=a|fixed|string)
(?<=t[abc]{1,3})
(?<=(abc){2,6})
(?<=^.*abc.*)
(?<=\G"[^"]+");
(?<=^(.....|.......)+)
\b(\w+)\b(?<!\b\1\b.*\1)

Помимо основного случая (?<=fixed-string), который должна поддерживать любая внешняя реализация, (?<=a|fixed|string) - очень желательный случай для поддержки.

Различные двигатели регулярных выражений имеют различный уровень поддержки регулярного выражения выше.

Посмотрим, как они реализованы в .NET и Java. (Это два вкуса, чье поведение позади меня изучало.)

Внедрение .NET

В реализации Microsoft.NET все перечисленные выше правила действительны, так как .NET реализует look-behind, используя режим справа налево со смещением начала в текущей позиции. Конструкция look-behind не генерирует никакой точки выбора сама по себе.

Однако, если вы используете группы захвата внутри look-behind, он начинает запутываться, поскольку атомы в шаблонах интерпретируются справа налево, как показано в этот пост. Это недостаток этого метода: вам нужно, чтобы ваш мозг думал прямо справа налево при написании внешнего вида.

реализация Java

Напротив, реализация регулярного выражения Java реализует обратную связь, повторно используя средства сравнения слева направо.

Сначала анализирует шаблон внутри внешнего вида для минимальной и максимальной длины шаблона. Затем look-behind реализуется, пытаясь сопоставить шаблон внутри слева направо, начиная с (current position - minimum length) до (current position - maximum length).

Нет ли чего-то недостающего? Да! Поскольку мы сопоставляем слева направо, мы должны убедиться, что совпадение заканчивается прямо в позиции перед входом в look-behind (current position). В Java это реализуется путем добавления node в конец шаблона внутри look-behind.

Эта реализация очень неэффективна, так как есть maximum - minimum + 1 точки выбора, созданные в самом внешнем образе, прежде чем мы даже поговорим о точках выбора, созданных шаблоном внутри look-behind.

Проверка привязки внешнего вида также неэффективна, поскольку она помещается в конце шаблона и не может обрезать точки выбора, которые явно безнадежны (те, которые намного превышают current position в середине шаблона).

Резюме

Как вы можете видеть, добавление поддержки look-behind непросто:

  • Подход справа налево представляется достаточно эффективным. Однако для других существующих конструкций требуется дополнительная спецификация поведения совпадения справа налево.
  • Подход к повторному использованию объектов совпадения слева направо сложно определить и очень неэффективен. Это также требует внедрения анализа шаблонов в спецификацию, чтобы производительность не выходила из окна.

(Обратите внимание, что я еще не рассмотрел поведение, когда look-behind используется внутри look-ahead и наоборот. Это также следует учитывать при определении семантики для конструкции look-behind).

Эти технические препятствия также упоминаются Вальдемар Хорват (который написал спецификацию регулярного выражения ES3) в почте, приведенной в ответ нилса:

Никто еще не представил четко сформулированное предложение для lookbehinds на столе. Lookbehinds трудно перевести на язык, используемый спецификацией, и получить довольно нечеткие, когда порядок оценки частей регулярного выражения имеет значение, что и происходит, если речь идет о захвате круглых скобок. Где вы начинаете искать lookbehind? Самый короткий первый, самый длинный первый или обратная строка? Жадный или нет? Возвращение в результаты?