Что это за два термина в понятной форме?
Что означают слова «ленивый» и «жадный» в контексте регулярных выражений?
Ответы (12)
Жадный поглотит как можно больше. На странице http://www.regular-expressions.info/repeat.html мы видим пример попытки сопоставить HTML-теги с <.+>
. Предположим, у вас есть следующее:
<em>Hello World</em>
Вы можете подумать, что <.+>
(.
означает любой символ не новой строки и +
означает один или несколько) будет соответствовать только <em>
и </em>
, хотя на самом деле он будет очень жадным , и перейти от первого <
к последнему >
. Это означает, что он будет соответствовать <em>Hello World</em>
вместо того, что вы хотели.
Выполнение ленивых действий (<.+?>
) предотвратит это. Добавляя ?
после +
, мы говорим ему повторять как можно реже, поэтому первое встреченное >
- это то место, где мы хотим остановить сопоставление.
Я рекомендую вам загрузить RegExr, отличный инструмент, который поможет вам изучить регулярные выражения - я использую это все время.
<[^>]+>
regex101.com/r/lW0cY6 / 1
- person alanbuchanan; 15.06.2015
«Жадный» означает совпадение самой длинной строки из возможных.
Ленивый означает соответствие самой короткой строке.
Например, жадный h.+l
соответствует 'hell'
в 'hello'
, а ленивый h.+?l
соответствует 'hel'
.
h.+l
соответствует 'helol'
в 'helolo'
, а ленивый h.+?l
соответствует 'hel'
.
- person v.shashenko; 21.03.2017
?
не делает .+
необязательным в h.+?l
. Разве не для этого нужен ?
? Кроме того, как бы вы различили две функции ?
- person FloatingRock; 14.04.2017
x?
означает, что x
не является обязательным, но +?
- это другой синтаксис. Это означает, что перестаньте искать то, что вам подходит - ленивое сопоставление.
- person slebetman; 14.04.2017
?
означает необязательный, а +?
означает ленивый. Следовательно, \+?
означает, что +
не является обязательным.
- person slebetman; 14.04.2017
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: _ 13_ вывод: stackoverflo w
выражение lazy reg: _ 14_ вывод: stacko verflow
re.match('(f)?(.*)', 'food').groups()
с re.match('(f)??(.*)', 'food').groups()
. В последнем случае (f)??
не будет соответствовать ведущей букве «f», хотя и может. Следовательно, 'f' будет соответствовать второй группе захвата '. *'. Я уверен, что вы можете построить пример с помощью '{n}?' тоже. По общему признанию, эти два используются очень редко.
- person smci; 16.11.2017
{n}?
эквивалентно {n}
. См. stackoverflow.com/questions/18006093/how -до-и-и-отличается
- person Théophile; 01.04.2021
Жадный означает, что ваше выражение будет соответствовать как можно большей группе, ленивое означает, что оно будет соответствовать минимально возможной группе. Для этой строки:
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>']
Вместо поиска до первого появления символа «>» извлекается вся строка. Это жадное поведение регулярного выражения по умолчанию или «взять все».
Ленивое сопоставление, с другой стороны, "занимает как можно меньше". Это можно сделать, добавив ?
в конце шаблона.
Пример:
re.findall('<.*?>', text)
#> ['<body>', '</body>']
Если вы хотите получить только первое совпадение, используйте вместо этого метод поиска.
re.search('<.*?>', text).group()
#> '<body>'
Источник: Примеры регулярных выражений Python
Жадный означает, что он будет поглощать ваш узор, пока не останется ни одного из них, и он не сможет больше смотреть.
Lazy остановится, как только встретит первый запрошенный вами шаблон.
Один из распространенных примеров, с которыми я часто сталкиваюсь, - это \s*-\s*?
регулярного выражения ([0-9]{2}\s*-\s*?[0-9]{7})
Первый \s*
классифицируется как жадный из-за *
и будет выглядеть как можно больше пробелов после того, как будут встречены цифры, а затем будет искать символ дефиса «-». Где второй \s*?
ленив из-за присутствия *?
, что означает, что он будет смотреть на первый пробельный символ и сразу же останавливаться.
\s
может соответствовать только пробелу, и после него должно быть 7 цифр.
- person Scratte; 03.02.2021
Лучше всего показать на примере. Нить. 192.168.1.1
и жадное регулярное выражение \b.+\b
Вы можете подумать, что это даст вам 1-й октет, но на самом деле он совпадает со всей строкой. Почему? Поскольку. + Является жадным, и жадное совпадение соответствует каждому символу в 192.168.1.1
, пока не достигнет конца строки. Это важный момент! Теперь он начинает возвращаться по одному символу за раз, пока не найдет совпадение для 3-го токена (\b
).
Если бы в начале была строка текстового файла размером 4 ГБ и 192.168.1.1, вы могли бы легко увидеть, как этот возврат с возвратом может вызвать проблему.
Чтобы сделать регулярное выражение не жадным (ленивым), поставьте вопросительный знак после жадного поиска, например
*?
??
+?
Теперь происходит то, что токен 2 (+?
) находит совпадение, регулярное выражение перемещается по символу, а затем пробует следующий токен (\b
), а не токен 2 (+?
). Так что ползет осторожно.
Жадные квантификаторы похожи на IRS / ATO
Если оно есть, они все заберут.
IRS соответствует этому регулярному выражению: .*
$50,000
Это будет соответствовать всему!
См. Здесь пример: Жадный пример
Нежадные квантификаторы - они берут как можно меньше
Если я прошу возврат налога, IRS внезапно становится не жадным, и они используют этот количественный показатель:
(.{2,5}?)([0-9]*)
против этого ввода: $50,000
Первая группа не является нуждающейся и соответствует только $5
, поэтому я получаю $5
возмещение в размере 50 000 долларов. Они не жадные. Берут как можно меньше.
См. Здесь: Нежадный пример.
Зачем беспокоиться?
Это становится важным, если вы пытаетесь сопоставить определенные части выражения. Иногда не хочется сочетать все.
Надеюсь, эта аналогия поможет вам вспомнить!
попробуйте понять следующее поведение:
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); // ""