На жадных против не жадных
Повторение в регулярном выражении по умолчанию: жадный : они пытаются сопоставить столько повторений, сколько возможно, и когда это не работает, и им приходится возвращаться назад, они пытаются сопоставить одно повторение за раз До тех пор, пока не будет найдено соответствие всей модели. В результате, когда совпадение, наконец, произойдет, жадное повторение будет соответствовать как много повторений.
?
как квантификатор повторения изменяет это поведение на не жадный , также называемый неохотный ( в, например, Java ) (и иногда "ленивый" «). Напротив, это повторение сначала будет пытаться сопоставить как можно больше нескольких повторений, и когда это не сработает, и они должны вернуться назад, они начинают сопоставлять еще одно повторение за раз. В результате, когда совпадение, наконец, произойдет, повторение с неохотой будет соответствовать как 1010 * нескольким повторениям, насколько это возможно.
Ссылки
Пример 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: от A до ZZ
Этот пример должен быть иллюстративным: он показывает, как шаблоны классов жадных, неохотных и отрицательных символов по-разному совпадают при одном и том же вводе.
eeAiiZooAuuZZeeeZZfff
Это совпадения для вышеуказанного ввода:
Вот визуальное представление того, что они совпали:
___n
/ \ n = negated character class
eeAiiZooAuuZZeeeZZfff r = reluctant
\_________/r / g = greedy
\____________/g
Похожие темы
Это ссылки на вопросы и ответы по стеку, которые охватывают некоторые темы, которые могут представлять интерес.
Один жадный повтор может перерасти другой