Что означает "ленивый" и "жадный" в контексте регулярных выражений?
Может ли кто-нибудь объяснить эти два термина понятным образом?
Ответы
Ответ 1
Жадность будет потреблять как можно больше. Из http://www.regular-expressions.info/repeat.html мы видим пример попытки сопоставления HTML-тегов с <.+>
. Предположим, что у вас есть следующее:
<em>Hello World</em>
Вы можете думать, что <.+>
(.
означает любой символ новой строки, а +
означает один или несколько) будет соответствовать только <em>
и </em>
, когда на самом деле это будет очень жадным, и перейти от первого <
к последнему >
. Это означает, что он будет соответствовать <em>Hello World</em>
вместо того, что вам нужно.
Сделать это ленивым (<.+?>
) предотвратит это. Добавив ?
после +
, мы попросим его повторить как можно меньше раз, поэтому первый >
, с которым он сталкивается, - это то, где мы хотим остановить сопоставление.
Я бы посоветовал вам скачать RegExr, отличный инструмент, который поможет вам исследовать регулярные выражения - я использую его все время.
Ответ 2
"Жадный" означает наименьшую возможную длину.
"Lazy" означает совпадение кратчайшей строки.
Например, жадный h.+l
соответствует 'hell'
в 'hello'
, но ленивый h.+?l
соответствует 'hel'
.
Ответ 3
+-------------------+-----------------+------------------------------+
| Greedy quantifier | Lazy quantifier | Description |
+-------------------+-----------------+------------------------------+
| * | *? | Star Quantifier: 0 or more |
| + | +? | Plus Quantifier: 1 or more |
| ? | ?? | Optional Quantifier: 0 or 1 |
| {n} | {n}? | Quantifier: exactly n |
| {n,} | {n,}? | Quantifier: n or more |
| {n,m} | {n,m}? | Quantifier: between n and m |
+-------------------+-----------------+------------------------------+
Добавить? к квантификатору, чтобы сделать его нелогичным, ленивым.
Пример:
тестовая строка: stackoverflow
жадное выражение reg: s.*o
вывод: stackoverflo w
lazy reg выражение: s.*?o
вывод: stacko verflow
Ответ 4
Жадный означает, что ваше выражение будет соответствовать как можно большему количеству групп, ленивое означает, что оно будет соответствовать наименьшей возможной группе. Для этой строки:
abcdefghijklmc
и это выражение:
a.*c
Жадный матч будет соответствовать всей строке, а ленивый матч будет соответствовать только первому abc
.
Ответ 5
Насколько я знаю, большинство движков regex жадно по умолчанию. Добавить знак вопроса в конце квантификатора позволит ленивое совпадение.
Как упоминалось в комментарии @Andre S.
- Жадный: продолжайте поиск до тех пор, пока условие не будет выполнено.
- Lazy: прекратить поиск, когда условие выполнено.
Обратитесь к приведенному ниже примеру для жадного и ленивого.
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Test {
public static void main(String args[]){
String money = "100000000999";
String greedyRegex = "100(0*)";
Pattern pattern = Pattern.compile(greedyRegex);
Matcher matcher = pattern.matcher(money);
while(matcher.find()){
System.out.println("I'm greeedy and I want " + matcher.group() + " dollars. This is the most I can get.");
}
String lazyRegex = "100(0*?)";
pattern = Pattern.compile(lazyRegex);
matcher = pattern.matcher(money);
while(matcher.find()){
System.out.println("I'm too lazy to get so much money, only " + matcher.group() + " dollars is enough for me");
}
}
}
Результат:
Я greeedy и хочу 100000000 долларов. Это самое лучшее, что я могу получить.
Мне слишком ленив, чтобы заработать столько денег, мне достаточно всего 100 долларов
Ответ 6
Взято из www.regular-expressions.info
Жадность: жадные кванторы сначала пытаются повторить токен столько раз
насколько это возможно, и постепенно отказывается от совпадений, когда двигатель отступает, чтобы найти
общий матч.
Лень: ленивый квантификатор сначала повторяет токен столько раз, сколько требуется, и
постепенно расширяет совпадение, так как двигатель возвращается к регулярному выражению
найти общий результат.
Ответ 7
От Регулярное выражение
Стандартные кванторы в регулярных выражения жадные, то есть они как можно больше, только давая при необходимости, чтобы соответствовать остаток регулярного выражения.
Используя ленивый квантификатор, выражение пытается минимальное совпадение первый.
Ответ 8
Лучше всего показано на примере. Строка. 192.168.1.1 и жадное регулярное выражение \b. +\B
Вы могли бы подумать, что это даст вам 1-й октет, но на самом деле совпадает со всей строкой. ЗАЧЕМ!!! Поскольку. + Жадный и жадный матч соответствует каждому символу в '192.168.1.1', пока он не достигнет конца строки. Это важный бит!!! Теперь он начинает возвращать один символ за раз, пока не найдет совпадение для третьего токена (\ b).
Если строка с текстовым файлом 4 ГБ и 192.168.1.1 была в начале, вы могли бы легко увидеть, как эта обратная трассировка вызовет проблему.
Чтобы сделать регулярное выражение, не жадное (ленивое), поставить знак вопроса после вашего жадного поиска, например
*?
??
+?
Теперь происходит токен 2 (+?) Находит совпадение, регулярное выражение перемещается вдоль символа, а затем пытается использовать следующий токен (\ b), а не токен 2 (+?). Таким образом, он ползет осторожно.
Ответ 9
Жадное соответствие. Поведение регулярных выражений по умолчанию должно быть жадным. Это означает, что он пытается извлечь как можно больше, пока не будет соответствовать шаблону, даже если меньшая часть была бы синтаксически достаточной.
Пример:
import re
text = "<body>Regex Greedy Matching Example </body>"
re.findall('<.*>', text)
#> ['<body>Regex Greedy Matching Example </body>']
Вместо сопоставления до первого появления ' > , он извлекал всю строку. Это жадность по умолчанию или "взять все поведение регулярного выражения".
Lazy matching, с другой стороны, "берет как можно меньше. Это можно сделать, добавив ?
в конец шаблона.
Пример:
re.findall('<.*?>', text)
#> ['<body>', '</body>']
Если вы хотите получить только первое совпадение, используйте вместо этого метод поиска.
re.search('<.*?>', text).group()
#> '<body>'
Источник: Примеры Python Regex
Ответ 10
Жадный означает, что он будет потреблять ваш узор, пока не останется ни одного из них, и он не сможет смотреть дальше.
Lazy остановится, как только он встретит первый шаблон, который вы запросили.
Одним из распространенных примеров, с которыми я часто сталкиваюсь, является \s*-\s*?
регулярного выражения ([0-9]{2}\s*-\s*?[0-9]{7})
Первый \s*
классифицируется как жадный из-за *
и будет выглядеть как можно больше белых пробелов после того, как будут встречаться цифры, а затем найдите тире "-". Где второй \s*?
является ленивым из-за присутствия *?
, что означает, что он будет выглядеть первым символом пробела и останавливаться прямо там.
Ответ 11
попытайтесь понять следующее поведение:
var input = "0014.2";
Regex r1 = new Regex("\\d+.{0,1}\\d+");
Regex r2 = new Regex("\\d*.{0,1}\\d*");
Console.WriteLine(r1.Match(input).Value); // "0014.2"
Console.WriteLine(r2.Match(input).Value); // "0014.2"
input = " 0014.2";
Console.WriteLine(r1.Match(input).Value); // "0014.2"
Console.WriteLine(r2.Match(input).Value); // " 0014"
input = " 0014.2";
Console.WriteLine(r1.Match(input).Value); // "0014.2"
Console.WriteLine(r2.Match(input).Value); // ""