Опережающая и ретроспективная проверка
В этой главе мы подробно рассмотрим поиск совпадений в JavaScript. Узнайте, как применять опережающую и ретроспективную проверку на практике.
Понимание продвинутых возможностей регулярных выражений JavaScript полезно любому разработчику, стремящемуся повысить свои навыки программирования. Среди наиболее мощных и функциональных инструментов этой области — утверждения опережающей и ретроспективной проверки. Они позволяют разработчикам искать паттерны в тексте, не включая сами паттерны в результат. Это руководство предлагает детальное изучение утверждений опережающей и ретроспективной проверки в JavaScript с многочисленными практическими примерами.
Регулярные выражения могут быть непростыми, и граничные случаи существуют. Особенно когда вы используете продвинутые концепции, такие как опережающая и ретроспективная проверка. Используйте онлайн-тестеры регулярных выражений или пишите модульные тесты, чтобы проверять свои выражения на различных входных данных и убедиться, что они работают ожидаемым образом.
Введение в утверждения опережающей и ретроспективной проверки
Утверждения опережающей и ретроспективной проверки — это утверждения нулевой ширины: они совпадают с позицией в строке, а не с реальными символами. Они позволяют проверять, существует или не существует заданный паттерн в определённой точке строки. Примечание: современные движки JavaScript (ES2018+) поддерживают ретроспективные утверждения переменной длины, хотя некоторые более старые среды могут требовать паттернов фиксированной длины.
Существует четыре утверждения, образованных комбинацией направления (вперёд/назад) и полярности (положительная/отрицательная):
| Утверждение | Синтаксис | Значение |
|---|---|---|
| Положительная опережающая проверка | (?=...) | Паттерн должен следовать после этой позиции |
| Отрицательная опережающая проверка | (?!...) | Паттерн не должен следовать после этой позиции |
| Положительная ретроспективная проверка | (?<=...) | Паттерн должен предшествовать этой позиции |
| Отрицательная ретроспективная проверка | (?<!...) | Паттерн не должен предшествовать этой позиции |
Почему «нулевая ширина» важна
Поскольку утверждения совпадают с позицией, а не с символами, проверяемый ими текст никогда не включается в совпадение, а позиция чтения движка регулярных выражений не смещается за него. Именно это делает их полезными: можно требовать контекст вокруг совпадения, не включая этот контекст в результат. Фрагмент ниже показывает разницу между обычной захватывающей группой и опережающей проверкой — обе убеждаются, что pie следует за apple, но только группа потребляет текст:
Если вы только знакомитесь с синтаксисом групп (...), см. Захватывающие группы — синтаксис lookaround использует те же скобки, но добавляет ?=, ?!, ?<= или ?<! сразу после открывающей скобки.
Положительная опережающая проверка
Утверждение положительной опережающей проверки проверяет наличие определённого паттерна впереди текущей позиции в строке. Оно обозначается (?=...). Следующий пример использует положительную опережающую проверку для поиска слова "apple", за которым следует слово "pie":
Опережающая проверка в регулярных выражениях JavaScript соответствует символам
Отрицательная опережающая проверка
Утверждение отрицательной опережающей проверки проверяет отсутствие определённого паттерна впереди текущей позиции. Оно обозначается (?!...). Следующий пример использует отрицательную опережающую проверку для поиска слова "apple", за которым не следует слово "pie":
Отрицательная опережающая проверка в регулярных выражениях JavaScript
Положительная ретроспективная проверка
Утверждение положительной ретроспективной проверки проверяет наличие определённого паттерна позади текущей позиции в строке. Оно обозначается (?<=...). Ниже приведён пример кода для поиска слова "pie", которому предшествует слово "apple":
Положительная ретроспективная проверка в регулярных выражениях JavaScript
Отрицательная ретроспективная проверка
Утверждение отрицательной ретроспективной проверки проверяет отсутствие определённого паттерна позади текущей позиции. Оно обозначается (?<!...). Вот пример для поиска слова "pie", которому не предшествует слово "apple":
Опережающая и ретроспективная проверка
Практическое применение опережающей и ретроспективной проверки
Проверка надёжности пароля
Требование к надёжным паролям является распространённой задачей в веб-приложениях. Утверждения опережающей проверки можно использовать для валидации различных условий к паролю без потребления символов.
Здесь каждый (?=...) — это отдельное требование, проверяемое с начала строки. Поскольку каждая опережающая проверка имеет нулевую ширину, все четыре независимо сканируют один и тот же текст, не мешая друг другу, а итоговый [A-Za-z\d@$!%*?&]{8,} — это то, что фактически потребляет пароль. Якоря ^ и $ привязывают проверку ко всей строке, а {8,} — это квантификатор, требующий не менее восьми символов.
Форматирование и разбор данных
Утверждения опережающей и ретроспективной проверки могут помочь при форматировании и разборе сложных структур данных. Хороший пример — вставка запятых в строку чисел для удобочитаемости:
Это работает путём замены каждой пустой позиции (\B, не-граница слова), за которой следует группа из трёх цифр, повторяющаяся до конца числа. Замыкающий (?!\d) гарантирует, что мы совпадаем только с позициями, где оставшиеся цифры делятся поровну на тройки, поэтому запятая не ставится в самом начале.
Извлечение суммы из цены
Ретроспективная проверка идеально подходит для захвата значения, которое стоит после известного маркера, без захвата самого маркера. Здесь мы извлекаем числовую сумму, следующую за знаком $:
Ретроспективная проверка (?<=\$) требует наличия $ непосредственно перед числом, но не включает его в результат, поэтому каждое совпадение содержит только цифру. Сравните это с использованием захватывающей группы — группа заставила бы вас читать сумму из match[1], тогда как ретроспективная проверка помещает значение прямо в совпадение.
Действие только при отсутствии следующего паттерна
Отрицательная опережающая проверка позволяет действовать в позиции на основе того, что не следует далее. Этот пример заменяет hello на HI только тогда, когда за ним не следует world:
Связанные темы
- Захватывающие группы — скобки, на которых строится синтаксис lookaround.
- Якоря: начало и конец строки —
^и$, часто используемые вместе с опережающей проверкой при валидации. - Квантификаторы, +, *, ? и
{n}— управление повторением внутри и за пределами утверждений. - Жадные и ленивые квантификаторы — как длина совпадения взаимодействует с lookaround.
Заключение
Освоение утверждений опережающей и ретроспективной проверки в JavaScript может значительно расширить вашу способность манипулировать строками и анализировать их. Эти мощные инструменты обеспечивают гибкость для проверки паттернов без потребления символов, что делает их незаменимыми при решении сложных задач обработки текста. Используя эти утверждения, разработчики могут создавать более эффективные регулярные выражения, что ведёт к более чистому и поддерживаемому коду.