Qual è la differenza tra .*? e. * espressioni regolari?


142

Sto cercando di dividere una stringa in due parti usando regex. La stringa è formattata come segue:

text to extract<number>

Ho usato (.*?)<e <(.*?)>che funziona bene, ma dopo aver letto un po 'in regex, ho appena iniziato a chiedermi perché ho bisogno ?delle espressioni. L'ho fatto solo dopo averli trovati attraverso questo sito, quindi non sono esattamente sicuro di quale sia la differenza.


Risposte:


172

È la differenza tra quantificatori avidi e non avidi.

Considera l'input 101000000000100.

Usare 1.*1, *è avido: si abbinerà fino alla fine, quindi tornerà indietro fino a quando non potrà abbinarsi 1, lasciandoti con 1010000000001.
.*?è non avido. *non corrisponderà a nulla, ma poi proverà ad abbinare caratteri extra fino a quando non corrisponderà 1, eventualmente abbinando 101.

Tutti i quantificatori hanno una modalità non-avido: .*?, .+?, .{2,6}?, e persino .??.

Nel tuo caso, un modello simile potrebbe essere <([^>]*)>: abbinare qualsiasi cosa tranne un segno maggiore di (in senso stretto, corrisponde a zero o più caratteri diversi da >in-Between <e >).

Vedi il cheat sheet di Quantifier .


Ah fantastico, mi piace l'ultimo di tutto tranne il segno>!
Doug,

1
Puoi spiegare o mostrare un esempio di come l'avido ?differisce dal non avido ???
AdrianHHH,

4
Sicuro. Per la stringa "abc", il regex /\w\w?\w/corrisponderebbe alla stringa completa "abc", perché ?è avido. /\w\w??\w/è pigro - corrisponderà solo "ab". Tornerà indietro e corrisponderà solo "abc"se fallisce in seguito.
Kobi,

184

Su goloso vs non goloso

La ripetizione in regex per impostazione predefinita è avida : cercano di abbinare il maggior numero possibile di ripetizioni, e quando questo non funziona e devono tornare indietro, cercano di abbinare un numero di ripetizioni alla volta, fino a quando una corrispondenza dell'intero modello è trovato. Di conseguenza, quando alla fine accade una partita, una ripetizione avida corrisponderebbe a quante più ripetizioni possibili.

Il ?quantificatore della ripetizione cambia questo comportamento in non avido , anche chiamato riluttante ( ad esempio Java ) (e talvolta "pigro"). Al contrario, questa ripetizione proverà prima ad abbinare il minor numero possibile di ripetizioni e quando questo non funziona e devono tornare indietro, iniziano ad abbinare un'altra ripetizione alla volta. Di conseguenza, quando finalmente si verifica una partita, una ripetizione riluttante corrisponderebbe al minor numero di ripetizioni possibile.

Riferimenti


Esempio 1: dalla A alla Z

Confrontiamo questi due schemi: A.*Ze A.*?Z.

Dato il seguente input:

eeeAiiZuuuuAoooZeeee

I modelli producono le seguenti corrispondenze:

Concentriamoci prima su cosa A.*Zfa. Quando corrisponde al primo A, il .*, essendo avido, cerca innanzitutto di abbinarne il maggior numero .possibile.

eeeAiiZuuuuAoooZeeee
   \_______________/
    A.* matched, Z can't match

Poiché Znon corrisponde, il motore fa un passo indietro e .*deve quindi corrispondere a uno in meno .:

eeeAiiZuuuuAoooZeeee
   \______________/
    A.* matched, Z still can't match

Questo succede più volte, fino a quando finalmente arriviamo a questo:

eeeAiiZuuuuAoooZeeee
   \__________/
    A.* matched, Z can now match

Ora Zpuò corrispondere, quindi lo schema generale corrisponde:

eeeAiiZuuuuAoooZeeee
   \___________/
    A.*Z matched

Al contrario, la riluttante ripetizione nelle A.*?Zprime partite il meno .possibile, e poi prendendo più .se necessario. Questo spiega perché trova due corrispondenze nell'input.

Ecco una rappresentazione visiva di ciò che corrispondevano ai due modelli:

eeeAiiZuuuuAoooZeeee
   \__/r   \___/r      r = reluctant
    \____g____/        g = greedy

Esempio: un'alternativa

In molte applicazioni, le due corrispondenze nell'input precedente sono ciò che si desidera, quindi .*?viene utilizzato un riluttante al posto dell'avido .*per evitare il super-accoppiamento. Per questo particolare schema, tuttavia, esiste un'alternativa migliore, usando la classe di caratteri negata.

Il modello A[^Z]*Ztrova anche le stesse due corrispondenze del A.*?Zmodello per l'input sopra ( come visto su ideone.com ). [^Z]è quella che viene definita una classe di caratteri negata : corrisponde a tutto tranne che a Z.

La differenza principale tra i due modelli è nelle prestazioni: essendo più rigorosa, la classe di caratteri negata può corrispondere solo in un modo per un dato input. Non importa se usi questo modificatore avido o riluttante per questo schema. In effetti, in alcuni gusti, puoi fare ancora meglio e usare quello che viene chiamato quantificatore possessivo, che non fa affatto marcia indietro.

Riferimenti


Esempio 2: dalla A alla ZZ

Questo esempio dovrebbe essere illustrativo: mostra come i modelli di classe di personaggi avidi, riluttanti e negati si abbinano in modo diverso dato lo stesso input.

eeAiiZooAuuZZeeeZZfff

Queste sono le corrispondenze per l'input sopra:

Ecco una rappresentazione visiva di ciò che hanno abbinato:

         ___n
        /   \              n = negated character class
eeAiiZooAuuZZeeeZZfff      r = reluctant
  \_________/r   /         g = greedy
   \____________/g

argomenti correlati

Questi sono collegamenti a domande e risposte su StackOverflow che trattano alcuni argomenti che potrebbero essere di interesse.

Una ripetizione avida può superare un altro


1
Volevo dire rubular.com, non ideone.com. Per gli altri: non rivedere questo post per me, lo farò io stesso alla prossima revisione, insieme ad altri esempi. Sentiti libero di dare feedback, suggerimenti, ecc. Nei commenti in modo da poter incorporare anche quelli.
poligenilubrificanti,


4
Questa risposta è stata aggiunta alle FAQ sulle espressioni regolari di Stack Overflow , in "Quantificatori> Altre informazioni sulle differenze ..."
aliteralmind

Questa risposta merita davvero di essere la risposta scelta !. Grazie mille per la tua spiegazione dettagliata.
masky007,

Ho aggiunto il tag non avido . Perché, perché la domanda ne aveva bisogno, ma anche perché incanalerà più utenti a questa grande risposta. In altre parole, se dai un'ottima risposta e la risposta usa un tag non presente nella domanda, allora aggiungi il tag perché l'OP non sapeva che il tag era rivelatore.
Guy Coder

21

Diciamo che hai:

<a></a>

<(.*)>corrisponderebbe a></adove <(.*?)>corrisponderebbe a. Quest'ultimo si ferma dopo la prima partita di >. Verifica la presenza di una o 0 corrispondenze .*seguite dall'espressione successiva.

La prima espressione <(.*)>non si interrompe quando corrisponde alla prima >. Continuerà fino all'ultima partita di >.


questo è più facile da capire rispetto alla spiegazione sopra.
Prometeo il
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.