О жадных и не жадных
Повторение в регулярном выражении по умолчанию жадное: они пытаются сопоставить как можно больше повторений, а когда это не работает и им приходится возвращаться, они пытаются сопоставить на одно повторение за раз меньше, пока найдено совпадение всего шаблона. В результате, когда совпадение, наконец, происходит, жадное повторение будет соответствовать как можно большему количеству повторений.
?
в качестве квантификатора повторения изменяет это поведение на не жадное, также называемое неохотным (, например, на Java) (а иногда и" ленивый "). Напротив, это повторение сначала будет пытаться сопоставить как можно несколько повторений, а когда это не сработает, и они должны вернуться назад, они начинают сопоставить еще одно повторение за раз. В результате, когда совпадение, наконец, происходит, повторение неохотно будет соответствовать как можно малому повторению.
использованная литература
Пример 1: от А до Я
Давайте сравним эти два паттерна: A.*Z
и A.*?Z
.
Учитывая следующий ввод:
eeeAiiZuuuuAoooZeeee
Шаблоны дают следующие совпадения:
Давайте сначала сосредоточимся на том, что делает A.*Z
. Когда он соответствует первому A
, .*
, будучи жадным, сначала пытается сопоставить как можно больше .
.
eeeAiiZuuuuAoooZeeee
\_______________/
A.* matched, Z can't match
Поскольку Z
не совпадает, движок выполняет возврат, и .*
должно соответствовать на единицу меньше .
:
eeeAiiZuuuuAoooZeeee
\______________/
A.* matched, Z still can't match
Это происходит еще несколько раз, пока, наконец, мы не придем к следующему:
eeeAiiZuuuuAoooZeeee
\__________/
A.* matched, Z can now match
Теперь Z
может совпадать, поэтому общий шаблон соответствует:
eeeAiiZuuuuAoooZeeee
\___________/
A.*Z matched
Напротив, неохотное повторение в A.*?Z
сначала соответствует как можно меньшему количеству .
, а затем при необходимости берется больше .
. Это объясняет, почему он находит два совпадения во входных данных.
Вот визуальное представление того, что совпадают между двумя шаблонами:
eeeAiiZuuuuAoooZeeee
\__/r \___/r r = reluctant
\____g____/ g = greedy
Пример: альтернатива
Во многих приложениях два совпадения во входных данных выше - это то, что нужно, таким образом, неохотное .*?
используется вместо жадного .*
, чтобы предотвратить чрезмерное совпадение. Однако для этого конкретного шаблона есть лучшая альтернатива, использующая инвертированный символьный класс.
Шаблон A[^Z]*Z
также находит те же два совпадения, что и шаблон A.*?Z
для указанного выше ввода (, как показано на ideone.com < / а>). [^Z]
- это то, что называется инвертированным классом символов: он соответствует чему угодно, кроме Z
.
Основное различие между этими двумя шаблонами заключается в производительности: будучи более строгим, инвертируемый символьный класс может соответствовать только одному способу для данного ввода. Неважно, используете ли вы модификатор «жадный» или «неохотный» для этого шаблона. Фактически, в некоторых вариантах вы можете добиться еще большего и использовать так называемый притяжательный квантификатор, который вообще не выполняет возврат.
использованная литература
Пример 2: От А до Я
Этот пример должен быть иллюстративным: он показывает, как шаблоны классов символов «жадный», «неохотный» и «отрицательный» совпадают по-разному при одном и том же вводе.
eeAiiZooAuuZZeeeZZfff
Это совпадения для приведенного выше ввода:
Вот визуальное представление того, что они соответствовали:
___n
/ \ n = negated character class
eeAiiZooAuuZZeeeZZfff r = reluctant
\_________/r / g = greedy
\____________/g
похожие темы
Это ссылки на вопросы и ответы по stackoverflow, которые охватывают некоторые темы, которые могут быть интересны.
Одно жадное повторение может превзойти другое
person
polygenelubricants
schedule
19.06.2010