Co oznaczają słowa "leniwy" i "chciwy" w kontekście wyrażeń regularnych?
Czy ktoś mógłby wyjaśnić te dwa terminy w zrozumiały sposób?
12 answers
Chciwy pochłonie jak najwięcej. Od http://www.regular-expressions.info/repeat.html widzimy przykład próby dopasowania znaczników HTML do <.+>
. Załóżmy, że masz:
<em>Hello World</em>
Możesz pomyśleć, że <.+>
(.
oznacza każdy znak nowej linii i +
oznacza jeden lub więcej ) pasuje Tylko do <em>
i </em>
, gdy w rzeczywistości będzie bardzo chciwy i przejdzie od pierwszego <
do ostatniego >
. Oznacza to, że będzie pasować Zamiast tego, czego chciałeś.
Uczynienie go leniwym (<.+?>
) zapobiegnie temu. Dodając ?
po +
, mówimy mu, aby powtarzał jak najmniej razy , więc pierwsza >
pojawia się, jest miejscem, w którym chcemy zatrzymać dopasowanie.
Zachęcam do pobrania RegExr , świetnego narzędzia, które pomoże Ci poznać wyrażenia regularne - używam go cały czas.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-06 19:39:16
'Greedy' oznacza dopasowanie najdłuższego możliwego ciągu.
'Lazy' oznacza dopasowanie najkrótszego możliwego ciągu.
Na przykład chciwy h.+l
pasuje 'hell'
w 'hello'
, ale leniwy h.+?l
pasuje 'hel'
.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-16 00:27:26
+-------------------+-----------------+------------------------------+
| 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 |
+-------------------+-----------------+------------------------------+
Dodaj ? do kwantyfikatora, aby uczynić go niegroźnym, czyli leniwym.
Przykład:
test string: stackoverflow
greedy reg expression : s.*o
wyjście: stackoverflo w
Lazy reg expression : s.*?o
wyjście: stacko verflow
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-31 23:14:15
Greedy oznacza, że Twoje wyrażenie będzie pasowało do jak największej grupy, lazy oznacza, że będzie pasowało do jak najmniejszej grupy. Dla tego ciągu:
abcdefghijklmc
I to wyrażenie:
a.*c
Chciwy mecz będzie pasował do całego ciągu, A leniwy mecz będzie pasował tylko do pierwszego abc
.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-02-20 06:30:38
Z tego co wiem, większość silników regex jest domyślnie zachłanna. Dodanie znaku zapytania na końcu quantifier umożliwi leniwe dopasowanie.
Jak wspomniał @Andre S w komentarzu.
- Greedy: szukaj dalej, dopóki warunek nie zostanie spełniony.
- Lazy: Przestań szukać, gdy warunek jest spełniony.
Zobacz poniższy przykład, co jest chciwe, a co leniwe.
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");
}
}
}
Rezultatem jest:
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
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-11-28 07:41:00
Wzięte z www.regular-expressions.info
Chciwość : chciwi kwantyfikatorzy najpierw próbują powtórzyć token tyle razy jak to możliwe, i stopniowo rezygnuje z zapałek, gdy silnik wycofuje się, aby znaleźć / align = "left" /
Lenistwo : leniwy kwantyfikator najpierw powtarza token tak kilka razy, jak jest to wymagane, i stopniowo rozszerza dopasowanie w miarę cofania silnika przez wyrażenie regularne do znajdź ogólne dopasowanie.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-10-19 08:34:34
Kwantyfikatory standardowe w regularnych wyrażenia są chciwe, co oznacza, że dopasować jak najwięcej, tylko dając powrót w razie potrzeby, aby dopasować pozostała część wyrażenia regularnego.
Używając leniwego kwantyfikatora, expression próbuje minimalnie dopasować najpierw.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-02-20 06:21:22
Chciwe dopasowanie. domyślnym zachowaniem wyrażeń regularnych jest zachłanność. Oznacza to, że stara się wyodrębnić jak najwięcej, dopóki nie będzie zgodny ze wzorem, nawet jeśli mniejsza część byłaby wystarczająca składniowo.
Przykład:
import re
text = "<body>Regex Greedy Matching Example </body>"
re.findall('<.*>', text)
#> ['<body>Regex Greedy Matching Example </body>']
Zamiast dopasowywania do pierwszego wystąpienia '>', wyodrębnia cały łańcuch. Jest to domyślne zachowanie greedy lub 'take it all' wyrażeń regularnych.
Leniwe dopasowanie, z drugiej strony, "takes as little as possible". Można tego dokonać dodając ?
na końcu wzorca.
Przykład:
re.findall('<.*?>', text)
#> ['<body>', '</body>']
Jeśli chcesz, aby pobrano tylko pierwsze dopasowanie, użyj metody wyszukiwania.
re.search('<.*?>', text).group()
#> '<body>'
Source: Python Regex Examples
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-21 05:41:50
Chciwy oznacza, że pochłonie Twój wzór, dopóki nie zostanie żaden z nich i nie będzie mógł dalej szukać.
Lazy zatrzyma się, gdy tylko napotka pierwszy wzorzec, o który prosiłeś.
Jednym z często spotykanych przykładów jest \s*-\s*?
z regex ([0-9]{2}\s*-\s*?[0-9]{7})
Pierwsza \s*
jest klasyfikowana jako zachłanna ze względu na *
i będzie wyglądać jak najwięcej białych spacji po napotkaniu cyfr, a następnie szukać znaku myślnika "-". Gdzie jako drugi \s*?
jest leniwy ze względu na teraźniejszość *?
, co oznacza, że będzie wyglądał na pierwszy znak białej spacji i zatrzyma się tam.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-06 15:41:32
Najlepiej pokazać na przykładzie. Sznurek. 192.168.1.1
i zachłanny regex \b.+\b
Można by pomyśleć, że daje to 1-szy oktet, ale w rzeczywistości pasuje do całego ciągu. Dlaczego? Ponieważ ... + jest chciwy i chciwy dopasowuje każdy znak w 192.168.1.1
, dopóki nie osiągnie końca łańcucha. To jest ważna część! Teraz zaczyna śledzić jedną postać na raz, aż znajdzie dopasowanie do trzeciego tokena (\b
).
Jeśli ciąg pliku tekstowego 4GB i 192.168.1.1 był na początku można łatwo zobaczyć, jak to cofanie może spowodować problem.
Aby Wyrażenie regularne Nie chciwe (lazy) umieścić znak zapytania po chciwym wyszukiwaniu np
*?
??
+?
To, co dzieje się teraz, to token 2 (+?
) znajduje dopasowanie, regex porusza się wzdłuż znaku, a następnie próbuje następnego tokena (\b
) zamiast tokena 2 (+?
). Więc skrada się ostrożnie.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-12-13 07:27:10
Chciwi Kwantyfikatorzy są jak Urząd Skarbowy / ATO
Jeśli tam jest, wezmą wszystko.IRS pasuje do tego regex: .*
$50,000
Zobacz tutaj przykład: Greedy-example
Nie-chciwe kwantyfikatory-biorą jak najmniej
Jeśli Poproszę o zwrot podatku, urząd skarbowy nagle staje się nie chciwy i używa tego kwantyfikatora:
(.{2,5}?)([0-9]*)
przeciw temu wejściu: $50,000
Pierwsza grupa to non-needy i tylko mecze $5
- więc dostaję $5
zwrot z $ 50,000 wejść. Nie są chciwi. Biorą jak najmniej.
Zobacz tutaj: nie-chciwy-przykład.
Po co się trudzić?Staje się ważne, jeśli próbujesz dopasować pewne części wyrażenia. Czasami nie chcesz dopasować wszystkiego.
Mam nadzieję, że ta analogia pomoże Ci zapamiętać!
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-08-10 04:25:43
Spróbuj zrozumieć następujące zachowanie:
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); // ""
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-10-30 06:31:14