Regex lookahead, lookbehind и атомные группы

314

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

(?!) - negative lookahead
(?=) - positive lookahead
(?<=) - positive lookbehind
(?<!) - negative lookbehind

(?>) - atomic group
Spidfire
источник
18
Почему на сайте regex нет такой простой таблицы? Вместо этого у них есть блоки текста, объясняющие только. регулярные
выражения.info/
3
@Whitecat Попробуйте: regex101.com regexr.com
Эндрю

Ответы:

853

Примеры

Учитывая строку foobarbarfoo:

bar(?=bar)     finds the 1st bar ("bar" which has "bar" after it)
bar(?!bar)     finds the 2nd bar ("bar" which does not have "bar" after it)
(?<=foo)bar    finds the 1st bar ("bar" which has "foo" before it)
(?<!foo)bar    finds the 2nd bar ("bar" which does not have "foo" before it)

Вы также можете объединить их:

(?<=foo)bar(?=bar)    finds the 1st bar ("bar" with "foo" before it and "bar" after it)

Определения

Смотри вперед позитивно (?=)

Найдите выражение A, где следует выражение B:

A(?=B)

Смотри вперед негатив (?!)

Найдите выражение A, где выражение B не следует:

A(?!B)

Смотреть за позитивом (?<=)

Найдите выражение A, где предшествует выражение B:

(?<=B)A

Смотреть за минусом (?<!)

Найдите выражение A, где выражение B не предшествует:

(?<!B)A

Атомные группы (?>)

Атомная группа выходит из группы и выбрасывает альтернативные шаблоны после первого сопоставленного шаблона внутри группы (обратное отслеживание отключено).

  • (?>foo|foot)sприменяется к footsбудет соответствовать его 1-й альтернативе foo, затем потерпит неудачу, поскольку sне следует сразу, и остановится, поскольку обратный ход отключен

Неатомарная группа позволит вернуться; если последующее сопоставление вперед не удастся, оно будет возвращаться и использовать альтернативные шаблоны, пока не будет найдено совпадение для всего выражения или пока не исчерпаны все возможности.

  • (foo|foot)sприменяется к footsволе:

    1. сопоставьте свою 1-ю альтернативу foo, затем потерпите неудачу, поскольку sне сразу следует foots, и вернитесь к ее 2-й альтернативе;
    2. сопоставьте его 2-й вариант foot, затем преуспейте, как sсразу следует foots, и остановитесь.

Некоторые ресурсы

Интернет-тестеры

skyfoot
источник
1
Что вы подразумеваете под "находит второй бар" часть? В выражении / строке есть только одна строка. Спасибо
зигги
2
@ziggy проверяется строка "foobarbarfoo". Как видите, в строке два foo и два бара.
скайфут
4
Может кто-нибудь объяснить, когда может понадобиться атомная группа? Если мне нужно сопоставить только первый вариант, зачем мне предлагать несколько вариантов?
arviman
2
Лучшее объяснение атомной группы в этом ответе . Может кто-нибудь отредактировать здесь, чтобы завершить этот диадический ответ?
Питер Краусс
5
Просто обратите внимание, что этот ответ был необходим, когда я попал в проект, который требовал серьезных регулярных выражений. Это отличное, краткое объяснение осмотров.
Том Кофлин
215

Lookarounds - это утверждения нулевой ширины. Они проверяют регулярное выражение (вправо или влево от текущей позиции - на основе впереди или сзади), успешно или не удается, когда найдено совпадение (на основании положительного или отрицательного значения), и отбрасывают совпадающую часть. Они не потребляют никаких символов - совпадение с регулярным выражением, следующее за ними (если оно есть), начнется с той же позиции курсора.

Читайте регулярно-expression.info для более подробной информации.

  • Позитивный взгляд:

Синтаксис:

(?=REGEX_1)REGEX_2

Совпадение только в случае совпадения REGEX_1; после сопоставления REGEX_1 совпадение отбрасывается, и поиск REGEX_2 начинается с той же позиции.

пример:

(?=[a-z0-9]{4}$)[a-z]{1,2}[0-9]{2,3}

REGEX_1 [a-z0-9]{4}$соответствует четырем буквенно-цифровым символам, за которыми следует конец строки.
REGEX_2 [a-z]{1,2}[0-9]{2,3}соответствует одной или двум буквам, за которыми следуют две или три цифры.

REGEX_1 гарантирует, что длина строки действительно равна 4, но не использует никаких символов, поэтому поиск REGEX_2 начинается с того же места. Теперь REGEX_2 удостоверяется, что строка соответствует некоторым другим правилам. Без заблаговременности он будет соответствовать строкам длиной три или пять.

  • Отрицательный взгляд

Синтаксис:

(?!REGEX_1)REGEX_2

Совпадение только в том случае, если REGEX_1 не совпадает; После проверки REGEX_1 поиск REGEX_2 начинается с той же позиции.

пример:

(?!.*\bFWORD\b)\w{10,30}$

Предварительная часть проверяет наличие FWORDв строке и завершается ошибкой, если находит ее. Если он не находит FWORD, предварительный просмотр завершается успешно, и следующая часть проверяет, что длина строки составляет от 10 до 30 и содержит только словаa-zA-Z0-9_

Взгляд назад похож на прогноз вперед: он просто смотрит позади текущей позиции курсора. Некоторые разновидности регулярных выражений, такие как javascript, не поддерживают косвенные утверждения. И большинство разновидностей, которые его поддерживают (PHP, Python и т. Д.), Требуют, чтобы эта часть просмотра имела фиксированную длину.

  • Атомные группы в основном отбрасывают / забывают последующие токены в группе, когда токен совпадает. Проверьте эту страницу для примеров атомных групп
Amarghosh
источник
следуя вашему объяснению, похоже, не работает в javascript, /(?=source)hello/.exec("source...hummhellosource ") = null. Ваше объяснение правильно?
Хелин Ван
@HelinWang Это объяснение верно. Ваше регулярное выражение ожидает строку, которая является одновременно источником и привет!
Амаргош
@jddxf Хотите уточнить?
Амаргош
@Amarghosh Я согласен с «Они проверяют регулярное выражение (вправо или влево от текущей позиции - на основе впереди или сзади), успешно или неудачно, когда найдено совпадение (на основании положительного или отрицательного результата), и отбрасывают совпадающее часть.". Таким образом, ожидающий запрос должен проверять регулярное выражение в направлении справа от текущей позиции, а синтаксис положительного предварительного просмотра должен быть равен x (? = Y)
jddxf
@ Amarghosh будет соответствовать, (?=REGEX_1)REGEX_2только если REGEX_2придет после REGEX_1 ?
аанди
0

Гроккинг смотрит вокруг быстро.
Как различить взгляд вперед и взгляд назад? Возьмите 2-минутный тур со мной:

(?=) - positive lookahead
(?<=) - positive lookbehind

предполагать

    A  B  C #in a line

Теперь мы спрашиваем B, где ты?
У B есть два решения, чтобы объявить это местоположение:

Во-первых, у B впереди есть A, а у C есть
два, у B впереди ( взгляд вперед) на C и позади (взгляд сзади) A.

Как мы видим, задние и передние противоположны в двух решениях.
Regex - это решение Два.

Исчисление
источник