Вопросительные знаки в регулярных выражениях
Я читаю ссылка на регулярные выражения и я думаю о ? и ?? письмена. Не могли бы вы объяснить мне некоторые примеры их полезности? Я их недостаточно понимаю.
спасибо
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 использования вопросительных знаков в регулярных выражениях.
-
Отрицательный Lookahead
отрицательные lookaheads используются, если вы хотите сопоставьте что-то, за чем не следует что-то еще. Отрицание продумывание конструкции скобках, с отворять скобки с вопросительным знаком и восклицательным знаком.
x(?!x2)
пример
- рассмотрим слово
There
-
теперь, по умолчанию регулярное выражение
e
найдет третью буквуe
в wordThere
.There ^
-
однако если вы не хотите, чтобы
e
, который сразу послеr
, тогда вы можете использовать RegExe(?!r)
. Теперь результат будет быть:There ^
- рассмотрим слово
-
Положительный Lookahead
положительный lookahead работает точно так же.
q(?=u)
соответствуетq
что сразу же следуетu
, безu
часть спичка. Положительная конструкция lookahead представляет собой пару скобок, с открывающей скобкой следует знак вопроса и знак равенства.пример
- рассмотрим слово
getting
-
теперь, по умолчанию регулярное выражение
t
найдет третью буквуt
в wordgetting
.getting ^
-
однако, если вы хотите
t
за которым немедленно следуетi
, тогда вы можете использовать RegExt(?=i)
. Теперь результат будет:getting ^
- рассмотрим слово
-
Группы Без Захвата
всякий раз, когда вы помещаете регулярное выражение в скобки
()
, они создайте нумерованную группу захвата. Он хранит часть строки соответствует части регулярного выражения внутри скобки.Если вам не нужна группа для захвата ее соответствия, вы можете оптимизировать это регулярное выражение в
(?:Value)