Ответы:
Жадный будет потреблять как можно больше. Из http://www.regular-expressions.info/repeat.html мы видим пример попытки сопоставить теги HTML с <.+>
. Предположим, у вас есть следующее:
<em>Hello World</em>
Вы можете подумать, что <.+>
( .
означает, что любой символ, не являющийся символом новой строки и +
означает один или несколько ), будет соответствовать только символ « <em>
и» </em>
, когда в действительности он будет очень жадным, и переходить от первого <
к последнему >
. Это означает, что он будет соответствовать <em>Hello World</em>
вместо того, что вы хотели.
Сделать это ленивым ( <.+?>
) предотвратит это. Добавляя ?
после +
, мы говорим, чтобы повторить как можно меньше раз , поэтому первый>
мы сталкиваемся, - это то, где мы хотим остановить сопоставление.
Я рекомендую вам загрузить RegExr , отличный инструмент, который поможет вам изучить регулярные выражения - я использую его постоянно.
<[^>]+>
regex101.com/r/lW0cY6/1
«Жадность» означает соответствие самой длинной строки.
«Ленивый» означает соответствие самой короткой возможной строки.
Например, жадные h.+l
матчи 'hell'
в 'hello'
но ленивые h.+?l
матчи 'hel'
.
h.+l
матчи 'helol'
в 'helolo'
но ленивые h.+?l
матчи 'hel'
.
x?
Означает, что x
это необязательно, но +?
другой синтаксис. Это значит перестать смотреть после того, как вы найдете что-то подходящее - ленивое соответствие.
?
означает необязательный и +?
означает ленивый. Поэтому \+?
средство +
необязательно.
+-------------------+-----------------+------------------------------+
| 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
выражение жадного выражения : s.*o
output: stackoverflo w
выражение lazy reg : s.*?o
output: верфи стека
re.match('(f)?(.*)', 'food').groups()
с re.match('(f)??(.*)', 'food').groups()
. В последнем (f)??
случае не будет совпадать с лидирующим 'f', хотя это может быть. Следовательно, 'f' будет соответствовать второй группе захвата '. *'. Я уверен, что вы можете создать пример с помощью '{n}?' тоже. По общему признанию, эти два очень редко используются.
Жадный означает, что ваше выражение будет соответствовать как можно большей группе, ленивый означает, что оно будет соответствовать наименьшей возможной группе. Для этой строки:
abcdefghijklmc
и это выражение:
a.*c
Жадное совпадение будет соответствовать всей строке, а ленивое совпадение - только первой abc
.
Насколько я знаю, большинство движков регулярных выражений по умолчанию жадные. Добавление знака вопроса в конце квантификатора позволит включить ленивое совпадение.
Как отметил @Andre S в комментарии.
Обратитесь к примеру ниже, чтобы узнать, что является жадным, а что ленивым.
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");
}
}
}
I'm greeedy and I want 100000000 dollars. This is the most I can get.
I'm too lazy to get so much money, only 100 dollars is enough for me
Взято с www.regular-expressions.info
Жадность : Жадные кванторы сначала пытается повторить маркер столько раз , сколько возможно, и постепенно отдает матчи как на откатывается двигателя , чтобы найти общий матч.
Ленивость : Ленивый квантификатор сначала повторяет токен столько раз, сколько требуется, и постепенно расширяет совпадение, когда двигатель откатывается через регулярное выражение, чтобы найти общее совпадение.
Стандартные квантификаторы в регулярных выражениях являются жадными, что означает, что они совпадают настолько, насколько могут, и отдают только по мере необходимости, чтобы соответствовать остатку регулярного выражения.
Используя ленивый квантификатор, выражение сначала пробует минимальное совпадение.
Жадное совпадение. Поведение регулярных выражений по умолчанию должно быть жадным. Это означает, что он пытается извлечь как можно больше, пока не будет соответствовать шаблону, даже если меньшая часть была бы синтаксически достаточной.
Пример:
import re
text = "<body>Regex Greedy Matching Example </body>"
re.findall('<.*>', text)
#> ['<body>Regex Greedy Matching Example </body>']
Вместо сопоставления до первого вхождения '>' он извлекал всю строку. Это стандартное поведение regex или «возьми все».
Ленивое сопоставление , с другой стороны, «занимает как можно меньше». Это может быть достигнуто путем добавления ?
в конце шаблона.
Пример:
re.findall('<.*?>', text)
#> ['<body>', '</body>']
Если вы хотите получить только первое совпадение, используйте вместо этого метод поиска.
re.search('<.*?>', text).group()
#> '<body>'
Источник: Python Regex Примеры
Жадность означает, что она будет поглощать ваш паттерн до тех пор, пока не останется ни одного из них, и она не сможет смотреть дальше.
Ленивый остановится, как только встретит первый шаблон, который вы запросили.
Одним из распространенных примеров, с которыми я часто сталкиваюсь, является \s*-\s*?
регулярное выражение([0-9]{2}\s*-\s*?[0-9]{7})
Первый \s*
классифицируется как жадный из-за того, что *
после того, как встретятся цифры, он будет искать как можно больше пробелов, а затем будет искать тире "-". Где, поскольку второй \s*?
ленив из-за настоящего, *?
это означает, что он будет смотреть первый символ пробела и остановится прямо там.
Лучше всего показывает пример. Строка. 192.168.1.1
и жадное регулярное выражение. \b.+\b
Вы можете подумать, что это даст вам 1-й октет, но на самом деле соответствует целой строке. Почему? Потому что. + Является жадным, и жадное совпадение соответствует каждому символу, 192.168.1.1
пока не достигнет конца строки. Это важный бит! Теперь он начинает возвращать по одному символу за раз, пока не найдет совпадение для 3-го токена ( \b
).
Если в начале строки был текстовый файл объемом 4 ГБ и 192.168.1.1, вы могли легко увидеть, как это может вызвать проблему с возвратом.
Чтобы сделать регулярное выражение не жадным (ленивым), поставьте знак вопроса после своего жадного поиска, например
*?
??
+?
Теперь происходит то, что токен 2 ( +?
) находит совпадение, регулярное выражение перемещается по персонажу и затем пытается использовать следующий токен ( \b
) вместо токена 2 ( +?
). Так что ползет осторожно.
Если он там, они придут и возьмут его. Они возьмут все это
Например, IRS совпадает с этим регулярным выражением: .*
$50,000
- IRS возьмет все это. Этот жадный .*{4}?
ERS
Смотрите здесь для примера: regexr.com/4t27f
С другой стороны, если я запрашиваю возврат налога, IRS внезапно становится не жадным, и они используют этот квантификатор:
(.{2}?)([0-9]*)
против этого выражения: $50,000
первая группа не нуждающаяся и только соответствует $5
- так что я получаю $5
возмещение. Остальное забрало дядя Сэм, чтобы потратить их впустую.
Смотрите здесь: Non-жадный пример .
Это становится важным, если вы пытаетесь сопоставить определенные части выражения. Иногда вы не хотите соответствовать всему.
попытаться понять следующее поведение:
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); // ""