яка різниця між ?:, ?! і? = в регулярному вираженні?


107

Я шукав значення цих виразів, але не міг зрозуміти точну різницю між ними. Це те, що вони кажуть:

  • ?: Збіг вирази, але не захоплюй його.
  • ?= Зіставити суфікс, але виключити його із захоплення.
  • ?! Збіг, якщо суфікс відсутній.

Я спробував використовувати їх у простому RegEx і отримав однакові результати для всіх. приклад: наступні 3 вирази дають дуже схожі результати.

  • [a-zA-Z0-9._-]+@[a-zA-Z0-9-]+(?!\.[a-zA-Z0-9]+)*
  • [a-zA-Z0-9._-]+@[a-zA-Z0-9-]+(?=\.[a-zA-Z0-9]+)*
  • [a-zA-Z0-9._-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9]+)*

Покажіть, будь ласка, свій тестовий випадок. Вони не повинні давати однакових результатів.
Бергі

@ sepp2k, це однакові результати в кількох випадках, один з них згадується у питанні.
РК Піддар

@ Bergi, я перевірив це на випадкових даних, що містять англійські слова, номери телефонів, URL-адреси, адреси електронної пошти, номери тощо.
РК Поддар,

4
@RKAgarwal Ах, я бачу, що ти там робив. Ви додали *після групи, тому вони просто ігноруються.
sepp2k

noobie Примітка : ви використовуєте їх лише на початку дужок, і дужки утворюють групу захоплення (різні набори дужок витягують різні розділи тексту).
Райан Тейлор

Відповіді:


152

Різниця між ?=і ?!полягає в тому, що перший вимагає відповідності даного вираження, а другий вимагає, щоб він не збігався. Наприклад, a(?=b)буде відповідати "a" в "ab", але не "a" в "ac". Тоді як a(?!b)буде відповідати "a" в "ac", але не "a" в "ab".

Різниця між ?:та в ?=тому, що ?=виключає вираз з усієї відповідності, тоді як ?:просто не створює групу захоплення. Так, наприклад, a(?:b)буде відповідати "ab" в "abc", тоді як a(?=b)буде відповідати лише "a" в "abc". a(b)буде відповідати "ab" в "abc" і створювати захоплення, що містить "b".


80
?:  is for non capturing group
?=  is for positive look ahead
?!  is for negative look ahead
?<= is for positive look behind
?<! is for negative look behind

Будь ласка, перевірте тут: http://www.regular-expressions.info/lookaround.html, щоб отримати дуже хороший підручник та приклади щодо пошуку у регулярних виразах.


15
І все ж JavaScript не знає позаду.
Бергі

1
Цей варіант є більш повним для загального регулярного вираження.
Ян Ян

/ (? <= ^ a) b / працював для мене в JavaScript! Здається, не існує навчального посібника для пошуку за Javascript в Інтернеті.
Й. Йошій

Лише останні версії браузерів почали підтримувати погляд у
списку

- anubhava Я не знаю жодної альтернативи / (? <= ^ A) b /, використовуючи чистий регулярний вираз. Можливо, я можу, але мені доведеться покладатися на функції зворотного дзвінка.
Й. Йошій

21

Для кращого розуміння давайте застосуємо три вирази плюс групу захоплення та проаналізуємо кожну поведінку.

  • () група захоплення - регекс всередині дужок повинен бути узгоджений і збіг створити групу захоплення
  • (?:) не захоплююча група - регулярний вираз у круглих дужках повинен відповідати, але не створює групу захоплення
  • (?=) позитивний погляд вперед - стверджує, що регулярний вираз повинен відповідати
  • (?!) негативний погляд вперед - стверджує, що неможливо зіставити регулярний вираз

Давайте звернемося q(u)iдо виходу . qвідповідає д і група захоплення uвідповідає U . Збирається сірник всередині групи захоплення і створюється група захоплення. Тож двигун продовжує с i. І iвідповідатиме i . Ця остання спроба матчу успішна. qui відповідає і створюється група захоплення з u .

Давайте звернемося q(?:u)iдо виходу . Знову ж , qвідповідає д і без захоплення групи uвідповідає U . Матч від групи, що не захоплює, береться, але група захоплення не створюється. Тож двигун продовжує с i. І iвідповідатиме i . Ця остання спроба матчу успішна. qui відповідає

Давайте звернемося q(?=u)iдо виходу . Показник позитивний і супроводжується іншим маркером. Знову qспівпадає q та uзбіг u . Знову-таки, відповідність з lookahead необхідно відмовитись, тому двигун відступає від iрядка до u . Шукати було успішно, тому двигун продовжує працювати i. Але iне може відповідати u . Тож ця спроба поєдинку провалюється.

Давайте звернемося q(?=u)uдо виходу . Показник позитивний і супроводжується іншим маркером. Знову qспівпадає q та uзбіг u . Збіг від lookahead необхідно відмовитись, тому двигун відступає від uрядка до u . Шукати було успішно, тому двигун продовжує працювати u. І uбуде відповідати u . Тож ця спроба поєдинку успішна. qu відповідає

Давайте звернемося q(?!i)uдо виходу . Навіть у цьому випадку lookahead є позитивним (тому iщо не відповідає) і супроводжується іншим маркером. Знову ж, qвідповідає q і iне відповідає u . Збіг від lookahead необхідно відмовитись, тому двигун відступає від uрядка до u . Шукати було успішно, тому двигун продовжує працювати u. І uбуде відповідати u . Тож ця спроба поєдинку успішна. qu відповідає

Отже, підсумовуючи, про реальну різницю між групами пошуку та невловими справами є все, якщо ви хочете просто перевірити існування чи перевірити та зберегти відповідність. Захоплення групи дорого, тому використовуйте їх розумно.


> тож двигун відступає від i в рядку до u. Шукати було успішно, тому двигун продовжує i. Але я не можу відповідати ЦЕ це зовсім заплутано. Чому крок назад , якщо це LOOKAHEAD ?
Зелений

1
@Green Важлива річ, яку потрібно зрозуміти щодо пошуку та інших конструкцій пошуку - це те, що, хоча вони проходять через рухи, щоб переконатися, чи здатний їх підвираз виражатись, вони насправді не "споживають" жоден текст. Це може бути трохи заплутано
freedev

7

Спробуйте відповідати foobarцим:

/foo(?=b)(.*)/
/foo(?!b)(.*)/

Перший регулярний вираз буде відповідати і поверне "бар" як перший підматч - (?=b)відповідає "b", але не споживає його, залишаючи його для наступних дужок.

Другий регулярний вираз НЕ буде відповідати, тому що він очікує, що за ним буде "foo" щось інше, ніж "b".

(?:...)має точно такий же ефект, як і простий (...), але він не повертає цю частину як підматч.


0

Найпростіший спосіб зрозуміти твердження - це трактувати їх як команду, вставлену в регулярний вираз. Коли двигун працює на твердження, він негайно перевірить стан, описане твердженням. Якщо результат вірний, продовжуйте виконувати регулярний вираз.


0

Це реальна різниця:

>>> re.match('a(?=b)bc', 'abc')
<Match...>
>>> re.match('a(?:b)c', 'abc')
<Match...>

# note:
>>> re.match('a(?=b)c', 'abc')
None

Якщо ви не дбаєте про вміст після "?:" Або "? =", "?:" І "? =" - це те саме. І те й інше добре використовувати.

Але якщо вам потрібен цей вміст для подальшого опрацювання (а не просто відповідати всій справі. У цьому випадку ви можете просто використовувати "a (b)") Ви повинні використовувати "? =" Замість цього. Причина "?:" Буде просто через це відійти.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.