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?

Author: smci, 2010-02-20

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.

 713
Author: Sampson,
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'.

 331
Author: slebetman,
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

 134
Author: Premraj,
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.

 59
Author: Carl Norum,
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
 18
Author: Eugene,
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.

 12
Author: Suganthan Madhavan Pillai,
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

Z Wyrażenie regularne

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.

 7
Author: Adriaan Stander,
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

 4
Author: Selva,
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.

 3
Author: stackFan,
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.

 3
Author: Jason Alcock,
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

To pasuje do wszystkiego!

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ć!

 3
Author: BKSpurgeon,
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); // ""
 -3
Author: FrankyHollywood,
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