Вопросительные знаки в регулярных выражениях

Я читаю ссылка на регулярные выражения и я думаю о ? и ?? письмена. Не могли бы вы объяснить мне некоторые примеры их полезности? Я их недостаточно понимаю.

спасибо

4 ответов


ключевая разница между ? и ?? проблемы лень. ?? ленив, ? нет.

предположим, вы хотите найти слово "автомобиль" в тексте, но вы не хотите ограничиваться только единственным "автомобилем"; вы также хотите сопоставить с множественным числом "автомобили".

вот например:

I own three cars.

теперь, если бы я хотел соответствовать слову "автомобиль"и я только хотел получить строку "автомобиль" взамен, я бы использовал ленивых ?? вот так:

cars??

это говорит: "ищите слово автомобиль или автомобили; если вы найдете либо, вернитесь car и больше ничего".

теперь, если бы я хотел сопоставить с теми же словами ("автомобиль "или" автомобили")и я хотел получить весь матч взамен, я бы использовал non-lazy ? вот так:

cars?

здесь написано: "ищите слово автомобиль или автомобили, и вернуть либо автомобиль или автомобили, что вы найдете".

в мире компьютерного программирования lazy обычно означает "оценивать только столько, сколько необходимо". Так ленивый ?? возвращает только столько, сколько необходимо для сопоставления; поскольку "s" в "cars" является необязательным, не возвращайте его. С другой стороны, не ленивый (иногда называют жадный) операции оценивают как можно больше, следовательно,? возвращает все совпадения, включая необязательные "с."

лично я считаю, что использую ? как способ сделать другие операторы регулярных выражений ленивыми (например,* и + операторы) чаще, чем я использую его для простой опциональности символов, но YMMV.

смотрите в коде

вот вышеприведенное реализовано в Clojure в качестве примера:

(re-find #"cars??" "I own three cars.")
;=> "car"

(re-find #"cars?" "I own three cars.")
;=> "cars"

элемент re-find - это функция, которая берет свой первый аргумент как регулярное выражение #"cars??" и возвращает первый матч он находит во втором аргументе "I own three cars."


это отличный вопрос, и мне потребовалось некоторое время, чтобы понять смысл ленивых ?? Квантор себя.

? - Дополнительный (жадный) Квантор

полезность ? достаточно легко понять. Если вы хотите найти оба http и https, вы можете использовать такой шаблон:

https?

этот шаблон будет соответствовать обоим входам, потому что это делает s необязательно.

?? - Необязательный (ленивый) Квантор

?? более тонкие. Обычно он делает то же самое ? делает. Он не изменяет результат true/false, когда вы спрашиваете: " удовлетворяет ли этот вход этому регулярному выражению?" вместо этого, это имеет отношение к вопросу:"какая часть этого входа соответствует этому регулярному выражению, и какие части принадлежат к группам?" если вход может удовлетворить шаблон более чем одним способом, двигатель решит, как сгруппировать его на основе ? и ?? (или * и *? или + и +?).

скажем, у вас есть набор входных данных, который вы хотите проверить и разобрать. Вот (по общему признанию, глупый) пример:

Input:       
http123
https456
httpsomething

Expected result:
Pass/Fail  Group 1   Group 2
Pass       http      123
Pass       https     456
Pass       http      something

вы попробуйте первое, что приходит на ум, это этой:

^(http)([a-z\d]+)$
Pass/Fail  Group 1   Group 2    Grouped correctly?
Pass       http      123        Yes
Pass       http      s456       No
Pass       http      something  Yes

они все проходят, но вы не можете использовать второй набор результатов, потому что вы хотели только 456 в группе 2.

Хорошо, давай попробовать еще раз. Скажем Группа 2 может быть буквами или цифрами, но не обоими:

(https?)([a-z]+|\d+)
Pass/Fail  Group 1   Group 2   Grouped correctly?
Pass       http      123       Yes
Pass       https     456       Yes
Pass       https     omething  No

теперь второй вход в порядке, но третий сгруппирован неправильно, потому что ? по умолчанию является жадным (+ тоже, но ? пришел первым). При принятии решения s является частью https? или [a-z]+|\d+, если результатом является проход в любом случае, regex engine всегда будет выбирать тот, который находится слева. Итак, группа 2 проигрывает s потому что Группа 1 засосала его.

чтобы исправить это, нужно сделать одно крошечное изменение:

(https??)([a-z]+|\d+)$
Pass/Fail  Group 1   Group 2    Grouped correctly?
Pass       http      123        Yes
Pass       https     456        Yes
Pass       http      something  Yes

по сути, это означает: "матч https если вам нужно, но посмотрите, если это все еще проходит, когда группа 1 просто http." двигатель понимает, что s может работать как часть [a-z]+|\d+, поэтому он предпочитает поместить его в группу 2.


? просто делает предыдущий элемент (символ, символ класса, группы) дополнительно:

colou?r

соответствует "цвет " и"цвет"

(swimming )?pool

матчи "бассейн " и"бассейн"

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


некоторые другие виды использования вопросительных знаков в регулярных выражениях

помимо того, что объясняется в других ответах,есть еще 3 использования вопросительных знаков в регулярных выражениях.    

  1. Отрицательный Lookahead

    отрицательные lookaheads используются, если вы хотите сопоставьте что-то, за чем не следует что-то еще. Отрицание продумывание конструкции скобках, с отворять скобки с вопросительным знаком и восклицательным знаком. x(?!x2)

    пример

    • рассмотрим слово There
    • теперь, по умолчанию регулярное выражение e найдет третью букву e в word There.

      There
        ^
      
    • однако если вы не хотите, чтобы e, который сразу после r, тогда вы можете использовать RegEx e(?!r). Теперь результат будет быть:

      There
          ^
      
  2. Положительный Lookahead

    положительный lookahead работает точно так же. q(?=u) соответствует q что сразу же следует u, без u часть спичка. Положительная конструкция lookahead представляет собой пару скобок, с открывающей скобкой следует знак вопроса и знак равенства.

    пример

    • рассмотрим слово getting
    • теперь, по умолчанию регулярное выражение t найдет третью букву t в word getting.

      getting
        ^
      
    • однако, если вы хотите t за которым немедленно следует i, тогда вы можете использовать RegEx t(?=i). Теперь результат будет:

      getting
         ^
      
  3. Группы Без Захвата

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

    Если вам не нужна группа для захвата ее соответствия, вы можете оптимизировать это регулярное выражение в

    (?:Value)
    

см. также этой и этой.