Regular Expressions
Жадные и ленивые кванторы
Поиск…
параметры
Кванторы | Описание |
---|---|
? | Сопоставьте предыдущий символ или подвыражение 0 или 1 раз (предпочтительно 1). |
* | Сопоставьте предыдущий символ или подвыражение 0 или более раз (как можно больше). |
+ | Сопоставьте предыдущий символ или подвыражение 1 или более раз (как можно больше). |
{n} | Сопоставьте предыдущий символ или подвыражение ровно n раз. |
{min,} | Сопоставьте предыдущий символ или подвыражение мин или более раз (как можно больше). |
{0,max} | Сопоставьте предыдущий символ или подвыражение макс или меньше (максимально приближайтесь к максимальному ). |
{min,max} | Сопоставьте предыдущий символ или подвыражение как минимум мин. Раз, но не более, чем максимальное время (максимально приближенное к максимуму ). |
Леновые кванторы | Описание |
?? | Сопоставьте предыдущий символ или подвыражение 0 или 1 раз (предпочтительно 0). |
*? | Сопоставьте предыдущий символ или подвыражение 0 или более раз (как можно меньше). |
+? | Сопоставьте предыдущий символ или подвыражение 1 или более раз (как можно меньше). |
{n}? | Сопоставьте предыдущий символ или подвыражение ровно n раз. Нет никакой разницы между жадной и ленивой версией. |
{min,}? | Сопоставьте предыдущий символ или подвыражение мин или более раз (как можно ближе к минимуму ). |
{0,max}? | Сопоставьте предыдущий символ или подвыражение макс или меньше (как можно меньше). |
{min,max}? | Сопоставьте предыдущий символ или подвыражение как минимум мин. Раз, но не более, чем максимальное время (как можно ближе к минимуму ). |
замечания
Жадность
Жадный квантификатор всегда пытается повторить подзадачу как можно дольше, прежде чем исследовать более короткие совпадения путем обратного отслеживания.
Как правило, жадный шаблон будет соответствовать самой длинной строке.
По умолчанию все кванторы являются жадными.
Лень
Ленивый (также называемый нежадным или неохотно) квантификатор всегда пытается повторить суб-схему , как несколько раз , как это возможно, прежде чем изучать более длинные матчи за счетом расширения.
Как правило, ленивый шаблон будет соответствовать кратчайшей возможной строке.
Сделать кванторы ленивыми, просто добавить ?
к существующему квантору, например +?
, {0,5}?
,
Концепция жадности и лености существует только в двигателях обратного слежения
Понятие жадного / ленивого квантора существует только в механизмах регулярных выражений обратного слежения. В механизмах регулярных выражений без обратного отслеживания или в системах с регулярным выражением, совместимых с POSIX, квантификаторы определяют только верхнюю границу и нижнюю границу повторения, не указав, как найти совпадение - эти механизмы всегда будут соответствовать самой длинной самой левой строке.
Жадность против лени
Учитывая следующий ввод:
aaaaaAlazyZgreeedyAlaaazyZaaaaa
Мы будем использовать два шаблона: один жадный: A.*Z
, и один ленивый: A.*?Z
Эти шаблоны дают следующие совпадения:
-
A.*Z
дает 1 совпадение:AlazyZgreeedyAlaaazyZ
(примеры: Regex101 , Rubular ) -
A.*?Z
дает 2 совпадения:AlazyZ
иAlaaazyZ
(примеры: Regex101 , Rubular )
Сначала сосредоточьтесь на том, что делает A.*Z
Когда он соответствует первому A
,. .*
, Будучи жадным, затем пытается сопоставить столько же .
насколько это возможно.
aaaaaAlazyZgreeedyAlaaazyZaaaaa
\________________________/
A.* matched, Z can't match
Так как Z
не соответствует, откат двигателя и .*
Должны совпадать с меньшим числом .
:
aaaaaAlazyZgreeedyAlaaazyZaaaaa
\_______________________/
A.* matched, Z can't match
Это происходит еще несколько раз, пока это не дойдет до конца:
aaaaaAlazyZgreeedyAlaaazyZaaaaa
\__________________/
A.* matched, Z can now match
Теперь Z
может совпадать, поэтому общий шаблон соответствует:
aaaaaAlazyZgreeedyAlaaazyZaaaaa
\___________________/
A.*Z matched
Напротив, неохотное (ленивое) повторение в A.*?Z
сначала совпадает с несколькими .
насколько это возможно, а затем принимать больше .
как необходимо. Это объясняет, почему он находит два совпадения на входе.
Вот визуальное представление того, что соответствовали двум шаблонам:
aaaaaAlazyZgreeedyAlaaazyZaaaaa
\____/l \______/l l = lazy
\_________g_________/ g = greedy
Пример, основанный на ответе, полученном полигенными смазочными материалами .
Стандарт POSIX не включает в себя ?
оператора, поэтому многие рексичные двигатели POSIX не имеют ленивого соответствия. Хотя рефакторинг, особенно с «самым большим трюком» , может помочь в некоторых случаях совпадения, единственный способ иметь истинное ленивое соответствие - использовать движок, который его поддерживает.
Границы с несколькими совпадениями
Когда у вас есть вход с четко определенными границами и вы ожидаете более одного совпадения в своей строке, у вас есть два варианта:
- Использование ленивых кванторов;
- Использование отрицательного символьного класса.
Рассмотрим следующее:
У вас простой механизм шаблонов, вы хотите заменить подстроки типа $[foo]
где foo
может быть любой строкой. Вы хотите заменить эту подстроку на все, что зависит от части между []
.
Вы можете попробовать что-то вроде \$\[(.*)\]
, А затем использовать первую группу захвата.
Проблема с этим заключается в том, что если у вас есть строка вроде something $[foo] lalala $[bar] something else
ваш матч будет
something $[foo] lalala $[bar] something else
| \______CG1______/|
\_______Match______/
Группа захвата foo] lalala $[bar
которая может быть или не быть действительной.
У вас есть два решения
Использование лености: в этом случае
*
ленивый - это один из способов найти правильные вещи. Таким образом, вы меняете свое выражение на\$\[(.*?)\]
Используя отрицательный класс символов:
[^\]]
вы меняете свое выражение на\$\[([^\]]*)\]
.
В обоих решениях результат будет таким же:
something $[foo] lalala $[bar] something else
| \_/| | \_/|
\____/ \____/
С группой захвата, соответственно, foo
и bar
.
Использование отрицательного символьного класса уменьшает проблему обратного отслеживания и может сэкономить ваш процессор много времени, когда дело доходит до больших входов.