Cosa significano "pigro" e "goloso" nel contesto delle espressioni regolari?


Risposte:


644

Greedy consumerà il più possibile. Da http://www.regular-expressions.info/repeat.html vediamo l'esempio del tentativo di abbinare i tag HTML con <.+>. Supponiamo di avere quanto segue:

<em>Hello World</em>

Potresti pensare che <.+>( .significa qualsiasi personaggio non newline e +significa uno o più ) corrisponderebbe solo al <em>e al </em>, quando in realtà sarà molto avido e passerà dal primo <all'ultimo >. Ciò significa che corrisponderà <em>Hello World</em>invece a quello che volevi.

Rendendolo pigro ( <.+?>) lo impedirà. Aggiungendo il ?dopo il +, gli diciamo di ripetere il minor numero di volte possibile , quindi il primo> che si incontra, è dove vogliamo fermare la corrispondenza.

Ti incoraggio a scaricare RegExr , un ottimo strumento che ti aiuterà a esplorare le espressioni regolari: lo uso sempre.


2
quindi se usi avido avrai 3 (1 elemento + 2 tag) corrispondenze o solo 1 corrispondenza (1 elemento)?
ajsie,

10
Corrisponderebbe solo 1 volta, a partire dal primo < e termina con l'ultimo > .
Sampson,

3
Ma renderlo pigro corrisponderebbe due volte, dandoci sia il tag di apertura che di chiusura, ignorando il testo in mezzo (poiché non si adatta all'espressione).
Sampson,

Un altro ottimo strumento che uso sempre: debuggex.com Ha anche una funzione "Incorpora in StackOverflow".
Ron van der Heijden,

8
Solo per aggiungere che esiste anche un modo goloso di farlo: <[^>]+> regex101.com/r/lW0cY6/1
alanbuchanan,

302

'Greedy' significa abbinare la stringa più lunga possibile.

'Lazy' significa abbinare la stringa più corta possibile.

Ad esempio, gli avidi h.+lpartite 'hell'in 'hello'ma i pigri h.+?lpartite 'hel'.


97
Brillante, così pigro si fermerà non appena la condizione l è soddisfatta, ma avido significa che si fermerà solo quando la condizione l non è più soddisfatta?
Andrew S,

3
Per tutte le persone che leggono il post: quantificatori avidi o pigri da soli non corrispondono alla sottostringa più lunga / più breve possibile. Dovresti usare un token goloso temperato o usare approcci non regex.
Wiktor Stribiżew,

3
@AndrewS Non essere confuso dal doppio ll nell'esempio. È piuttosto pigro corrisponderà alla sottostringa più corta possibile mentre avido corrisponderà alla più lunga possibile. Greedy h.+lpartite 'helol'in 'helolo'ma le pigre h.+?lpartite 'hel'.
v.shashenko,

3
@FloatingRock: No. x?significa che xè facoltativo ma ha +?una sintassi diversa. Significa smettere di prendersi cura di trovare qualcosa che corrisponda - corrispondenza pigra.
slebetman,

1
@FloatingRock: quanto a come si differenzia la diversa sintassi, semplice: ?significa opzionale e +?significa pigro. Pertanto \+?significa che +è facoltativo.
slebetman,

114
+-------------------+-----------------+------------------------------+
| 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  |
+-------------------+-----------------+------------------------------+

Aggiungere un ? a un quantificatore per renderlo non gradevole, cioè pigro.

Esempio:
stringa di test: stackoverflow
espressione greedy reg : s.*ooutput: stackoverflo w
espressione pigra reg : s.*?ooutput: stacko verflow


2
non è ?? equivalente a ? . Allo stesso modo, non è {n}? equivalente a {n}
Numero 945

5
@BreakingBenjamin: no ?? non equivale a?, quando ha la scelta di restituire 0 o 1 occorrenza, sceglierà l'alternativa 0 (pigra). Per vedere la differenza, confronta re.match('(f)?(.*)', 'food').groups()con re.match('(f)??(.*)', 'food').groups(). In quest'ultimo caso, (f)??non corrisponderà alla 'f' principale anche se potrebbe. Quindi la 'f' verrà abbinata al secondo gruppo di acquisizione '. *'. Sono sicuro che puoi costruire un esempio con '{n}?' pure. Certamente questi due sono usati molto raramente.
smci,

55

Greedy significa che la tua espressione corrisponderà al gruppo più grande possibile, pigra significa che corrisponderà al gruppo più piccolo possibile. Per questa stringa:

abcdefghijklmc

e questa espressione:

a.*c

Una partita golosa corrisponderà all'intera stringa e una partita pigra corrisponderà solo alla prima abc.


16

Per quanto ne so, la maggior parte dei motori regex è avida per impostazione predefinita. L'aggiunta di un punto interrogativo alla fine del quantificatore consentirà la corrispondenza pigra.

Come @Andre S menzionato nel commento.

  • Greedy: continua a cercare fino a quando la condizione non è soddisfatta.
  • Lazy: interrompere la ricerca una volta soddisfatta la condizione.

Fare riferimento all'esempio seguente per ciò che è avido e ciò che è pigro.

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");
        }
    }
}


Il risultato è:

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

9

Tratto da www.regular-expressions.info

Avidità : i quantificatori avidi prima cercano di ripetere il token il maggior numero di volte possibile, e gradualmente abbandonano le partite mentre il motore fa marcia indietro per trovare una partita complessiva.

Pigrizia : il quantificatore pigro prima ripete il token tutte le volte che è necessario e espande gradualmente la partita mentre il motore indietreggia attraverso la regex per trovare una corrispondenza generale.


6

Dall'espressione regolare

I quantificatori standard nelle espressioni regolari sono avidi, nel senso che corrispondono il più possibile, restituendo solo quanto necessario per abbinare il resto della regex.

Usando un quantificatore pigro, l'espressione prova prima la corrispondenza minima.


4

Abbinamento goloso. Il comportamento predefinito delle espressioni regolari deve essere avido. Ciò significa che tenta di estrarre il più possibile fino a quando non è conforme a un modello anche quando una parte più piccola sarebbe stata sintatticamente sufficiente.

Esempio:

import re
text = "<body>Regex Greedy Matching Example </body>"
re.findall('<.*>', text)
#> ['<body>Regex Greedy Matching Example </body>']

Invece di corrispondere fino alla prima occorrenza di '>', ha estratto l'intera stringa. Questo è il comportamento predefinito di avidità o "accetta tutto" di regex.

L'abbinamento pigro , d'altra parte, "prende il meno possibile". Questo può essere effettuato aggiungendo ?a alla fine del pattern.

Esempio:

re.findall('<.*?>', text)
#> ['<body>', '</body>']

Se si desidera recuperare solo la prima corrispondenza, utilizzare invece il metodo di ricerca.

re.search('<.*?>', text).group()
#> '<body>'

Fonte: esempi Python Regex


3

Greedy significa che consumerà il tuo schema fino a quando non ne rimarrà nessuno e non potrà cercare oltre.

Lazy si fermerà non appena incontrerà il primo schema richiesto.

Un esempio comune che incontro spesso è \s*-\s*?di regex([0-9]{2}\s*-\s*?[0-9]{7})

Il primo \s*è classificato come avido a causa di *e cercherà il maggior numero di spazi bianchi possibile dopo che le cifre sono state rilevate e quindi cercherà un trattino "-". Dove come il secondo \s*?è pigro a causa del presente, *?ciò significa che sembrerà il primo personaggio dello spazio bianco e si fermerà proprio lì.


3

Meglio mostrato dall'esempio. Corda. 192.168.1.1e una regex avida \b.+\b Potresti pensare che questo ti darebbe il 1 ° ottetto, ma in realtà corrisponde a tutta la stringa. Perché? Perché. + È goloso e una partita golosa corrisponde a tutti i personaggi 192.168.1.1fino a quando non raggiunge la fine della stringa. Questa è la parte importante! Ora inizia a tornare indietro di un personaggio alla volta fino a quando non trova una corrispondenza per il 3 ° token ( \b).

Se la stringa fosse un file di testo da 4 GB e 192.168.1.1 all'inizio, si vedeva facilmente come questo backtracking potesse causare un problema.

Per rendere un regex non avido (pigro) metti un punto interrogativo dopo la tua avida ricerca, ad es

*?
??
+?

Quello che succede ora è il token 2 ( +?) trova una corrispondenza, regex si sposta lungo un personaggio e quindi prova il token successivo ( \b) anziché il token 2 ( +?). Quindi si insinua con cautela.


0

I quantificatori avidi sono come l'IRS / ATO: prendono il più possibile:

Se è lì, verranno e lo prenderanno. Prenderanno tutto:

Ad esempio, l'IRS corrisponde a questo regex: .*

$50,000 - L'IRS prenderà tutto. Quelli golosi.*{4}? ERS

Vedi qui per un esempio: regexr.com/4t27f

Quantificatori non avidi - prendono il meno possibile

D'altra parte, se chiedo un rimborso fiscale, l'IRS improvviso diventa non avido e usano questo quantificatore:

(.{2}?)([0-9]*)contro questa espressione: $50,000il primo gruppo è non necessario e corrisponde solo $5- quindi ottengo un$5 rimborso. Il resto è preso dallo zio Sam per essere speso inutilmente.

Vedi qui: esempio non avido .

Perché preoccuparsi?

Diventa importante se stai cercando di abbinare determinate parti di un'espressione. A volte non vuoi abbinare tutto.


-3

prova a capire il seguente comportamento:

    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); // ""
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.