2013-09-24 10 views
6

Oggi mi sono imbattuto la seguente espressione regolare e voleva sapere cosa Rubino avrebbe fatto con esso:significato di un `+` a seguito di un `*`, quando quest'ultimo viene utilizzato come un quantificatore in un'espressione regolare

> "#a" =~ /^[\W].*+$/ 
=> 0 
> "1a" =~ /^[\W].*+$/ 
=> nil 

In questo caso, Ruby sembra ignorare il carattere +. Se ciò non è corretto, non sono sicuro di cosa stia facendo. Immagino che non venga interpretato come un quantificatore, dal momento che lo * non è stato scappato e viene utilizzato come quantificatore. In Perl/Ruby regex, a volte quando un carattere (ad es., -) viene utilizzato in un contesto in cui non può essere interpretato come un carattere speciale, viene considerato letterale. Ma se ciò accadesse in questo caso, mi aspetterei che la prima corrispondenza fallisse, dal momento che non c'è lo + nella stringa lvalue.

È un uso sottilmente corretto del carattere +? Il comportamento sopra è un bug? Mi manca qualcosa di ovvio?

+0

Dove ti sei imbattuto in questa espressione regolare? –

+0

In alcuni contenuti di sicurezza di terze parti incontrati durante il mio lavoro. Immagino che la regex non sia ciò che l'autore intendeva, ma quando ho visto il comportamento di Ruby, ho iniziato ad avere domande su questa ipotesi. –

risposta

5

Bene, si può certamente usare un + dopo un *. Puoi leggere un po 'su di esso on this site. Lo + dopo lo * è chiamato quantificatore possessivo.

Cosa fa? Previene lo * dal backtracking.

Di solito, quando si ha qualcosa come .*c e utilizzare questo per abbinare abcde, il .* sarà prima partita l'intera stringa (abcde) e dal momento che l'espressione regolare non può corrispondere c dopo la .*, il motore sarà tornare indietro di un carattere alla tempo di controllare se c'è una corrispondenza (questo è backtracking).

Una volta retrocesso a c, si otterrà la partita abc da abcde.

Ora, immaginate che il motore deve fare marcia indietro un paio di centinaia di personaggi, e se avete nidificato i gruppi e multiple * (o + o la forma {m,n}), si può rapidamente finire con migliaia, milioni di caratteri fare marcia indietro, chiamato catastrophic backtracking.

È qui che i quantificatori possessivi sono utili. In realtà impediscono qualsiasi forma di backtracking. Nella suddetta espressione regolare che ho menzionato, abcde non verrà corrisposto da .*+c. Una volta che lo .*+ ha consumato l'intera stringa, non può tornare indietro e poiché non c'è lo c alla fine della stringa, la corrispondenza non riesce.

Quindi, un altro possibile uso di quantificatori possessivi è che possono migliorare le prestazioni di alcune espressioni regolari, a condizione che il motore possa supportarlo.

Per il vostro regex /^[\W].*+$/, non penso che ci sia alcun miglioramento (forse un piccolo miglioramento) che il quantificatore possessivo fornisce però. E per ultimo, potrebbe essere facilmente riscritto come /^\W.*+$/.

+0

L'unico miglioramento che si può ottenere è che il motore non deve salvare gli stati intermedi mentre sta andando incontro alla corrispondenza di '. *' (Che * dovrebbe * essere usato per il backtracking in seguito).Ma il modello non tornerà mai indietro, quindi non ci sono risparmi a tal fine. –

+0

Eccellente storno - grazie. –

+0

@EricWalker Prego :) – Jerry

Problemi correlati