Come funzionano effettivamente le espressioni regolari?


30

Supponi di avere un documento con un saggio scritto. Vuoi analizzare questo saggio per selezionare solo determinate parole. Freddo.

L'uso di un'espressione regolare è più veloce dell'analisi del file riga per riga e parola per parola alla ricerca di una corrispondenza? In tal caso, come funziona? Come puoi andare più veloce di guardare ogni parola?


5
Supponi (implicando zero prove) che un'espressione regolare sarà più veloce ma non sai perché lo sia? Forse dovresti riconsiderare il tuo presupposto allora.
pdr,

3
quindi, il presupposto. se avessi delle prove, non sarebbe una, giusto?
LazeR

4
Non è questo il punto. Il punto è ciò che ti ha portato a questa ipotesi ... Non hai bisogno di prove per le tue domande, ma hai bisogno di un ragionamento per le tue assunzioni.
yannis,

1
err, non tutti i caratteri della stringa di input stanno semplicemente spostando una macchina a stati al prossimo stato. Non vedo come chiunque possa rallentare
quell'operazione

2
Non sono sicuro di più veloce, ma il motivo principale per cui utilizzo le espressioni regolari è dovuto all'eleganza di schemi di corrispondenza complessi, semplicemente non troverai un modo migliore per articolarlo in un ambiente di codifica.
Mantorok,

Risposte:


47

Come funziona?

Dai un'occhiata alla teoria degli automi

In breve, ogni espressione regolare ha un automa finito equivalente e può essere compilata e ottimizzata in un automa finito. Gli algoritmi coinvolti possono essere trovati in molti libri compilatori. Questi algoritmi sono usati da programmi unix come awk e grep.

Tuttavia, la maggior parte dei linguaggi di programmazione moderni (Perl, Python, Ruby, Java (e linguaggi basati su JVM), C #) non usano questo approccio. Usano un approccio ricorsivo di backtracking, che compila un'espressione regolare in un albero o una sequenza di costrutti che rappresentano vari sottogruppi dell'espressione regolare. La maggior parte delle sintassi moderne di "espressione regolare" offrono riferimenti indietro che sono al di fuori del gruppo di linguaggi regolari (non hanno rappresentazione in automi finiti), che sono banalmente implementabili in un approccio ricorsivo al backtracking.

L'ottimizzazione di solito produce una macchina a stati più efficiente. Ad esempio: considera aaaab | aaaac | aaaad, un normale programmatore può ottenere l'implementazione della ricerca semplice ma meno efficiente (confrontando tre stringhe separatamente) in dieci minuti; ma rendendolo conto equivale a aaaa [bcd], una ricerca migliore può essere fatta cercando i primi quattro "a", quindi testando il quinto carattere contro [b, c, d]. Il processo di ottimizzazione è stato uno dei miei lavori di compilazione a casa molti anni fa, quindi presumo che lo sia anche nella maggior parte dei moderni motori di espressione regolare.

D'altra parte, le macchine a stati hanno qualche vantaggio quando accettano stringhe perché usano più spazio rispetto a una "banale implementazione". Si consideri un programma per non sfuggire alle virgolette sulle stringhe SQL, ovvero: 1) inizia e termina con virgolette singole; 2) le virgolette singole sfuggono a due virgolette singole consecutive. Quindi: input ['a' ''] dovrebbe produrre output [a ']. Con una macchina a stati, le virgolette singole consecutive sono gestite da due stati. Questi due stati hanno lo scopo di ricordare la cronologia di input in modo tale che ciascun carattere di input venga elaborato esattamente una sola volta, come illustrato di seguito:

...
S1->'->S2
S1->*->S1, output *, * can be any other character 
S2->'->S1, output '
S2->*->END, end the current string

Quindi, secondo me, l'espressione regolare può essere più lenta in alcuni casi banali, ma di solito più veloce di un algoritmo di ricerca creato manualmente, dato che l'ottimizzazione non può essere eseguita in modo affidabile dall'uomo.

(Anche in casi banali come la ricerca di una stringa, un motore intelligente può riconoscere il singolo percorso nella mappa degli stati e ridurre quella parte a un semplice confronto di stringhe ed evitare la gestione degli stati.)

Un motore specifico da un framework / libreria può essere lento perché il motore fa molte altre cose di cui un programmatore di solito non ha bisogno. Esempio: la classe Regex in .NET crea un gruppo di oggetti tra cui Match, Gruppi e Catture.


2
Non avrei potuto dirlo meglio. L'unica cosa che aggiungerei: le espressioni regolari possono compensare anche i programmatori pigri. Nell'esempio che hai menzionato aaaab|aaaac|aaaadvs. aaaa[bcd]. Vale la pena dichiarare esplicitamente che i due sono matematicamente equivalenti e producono lo stesso DFA, dando così ai programmatori una maggiore libertà di rappresentare un'espressione regolare in un modo sensato (non che questa è una pratica comune, ma ... sai). ..
riwalk

Grazie, questo in realtà aveva senso grazie alla classe di automi che ho preso
lazeR

È questo un esempio di banale problema in cui regex è eccessivo ? :
stackoverflow.com/questions/18955099/…

17

Le espressioni regolari sembrano veloci perché hai computer veloci.

Negli anni '80, quando 1 MIPS era un computer veloce, le espressioni regolari rappresentavano un settore piuttosto preoccupante, preoccupato e di ricerca perché erano lente e brutte e richiedevano un intenso calcolo. Lo sviluppo di algoritmi intelligenti è stato seguito e ha aiutato, ma per tutti gli scopi pratici in questi giorni stai vedendo il miracolo delle macchine veloci incartare sulle crepe.


2
Se stai solo cercando una sola parola, entrambi i metodi sono uguali (o regexp è leggermente più lento). Ma data un'espressione complessa (e un testo di dimensioni ragionevolmente grandi) l'espressione regolare sarà probabilmente più veloce di una semplice ricerca (supponendo che tu scriva semplicemente la ricerca semplice (puoi sempre scrivere una ricerca complessa che è altrettanto veloce)). Ora il tempo è significativo è una domanda troppo generica e dovrai esaminarla caso per caso.
Martin York,

3
-1. La teoria dell'espressione regolare risale agli anni '50 ed è stata determinante nella creazione di analizzatori lessicali (e per estensione, compilatori). Creano macchine a stati molto efficienti che (dimostrabilmente) usano il minor numero possibile di stati. Le macchine a stati risultanti possono abbinare modelli complessi molto più velocemente di qualsiasi cosa tu possa scrivere a mano. Sembrano veloci perché sono veloci.
riwalk

Potrebbe essermi perso un po 'il punto. Possono essere "veloci", ma è tutto relativo - c'è ancora un sacco di lavoro da fare. Alcune delle altre risposte qui portano anche la lettura.
quick_now

Questa risposta è pertinente alla domanda? e come 13 voti?
Sadanand,

7

Perché pensi che siano più veloci della ricerca del documento?

Ci sono alcuni trucchi che puoi fare, ad es. se stai cercando una parola da 10 lettere che inizia con A e termina con B, quindi se trovi A e il carattere 9 posizioni più avanti non è B, puoi saltarne alcune. vedi algoritmo Knuth – Morris – Pratt



5

I regEx sono comparativamente più veloci nel codice che potresti scrivere perché la maggior parte delle biblioteche sono il risultato di molti sviluppatori che trascorrono molti anni ottimizzandoli per ottenere il massimo delle prestazioni possibili. È difficile per un singolo individuo duplicarlo nel proprio codice di ricerca.


4
s / squeak / squeeze /?
Péter Török,

4

La tua premessa di base è sbagliata.

Le espressioni regolari non sono sempre più veloci di una semplice ricerca. Tutto dipende dal contesto. Dipende dalla complessità dell'espressione, dalla lunghezza del documento da cercare e da tutta una serie di fattori.

Quello che succede è che l'espressione regolare verrà compilata in un semplice parser (che richiede tempo). Pertanto, se il documento è di piccole dimensioni, questo tempo extra supererà qualsiasi vantaggio. Inoltre, se l'espressione è semplice, allora l'espressione regolare non ti darà alcun vantaggio.

Se l'espressione è complessa e il documento è sufficientemente grande, puoi ottenere alcuni vantaggi. Se questo sia abbastanza significativo da considerare le espressioni regolari più veloci dipenderà molto dallo sforzo che vuoi fare nella ricerca (anche le espressioni regolari possono avere alcune ottimizzazioni che una biblioteca potrebbe fornire che non avresti pensato a te stesso).

Quello che sto cercando di dire è che non esiste una risposta generalizzata e generale. Se avessi un'espressione specifica (e una dimensione nota del documento), allora potresti dire derivare una risposta sì / no dal fatto che l'espressione sarà più veloce di una semplice ricerca (e perché).

Il vero vantaggio delle espressioni regolari è che una volta capito come scriverle, la capacità di esprimere una ricerca complessa in modo conciso. Poiché si tratta di un modulo generalizzato, è quindi possibile creare strumenti che consentano le ricerche in modo utile nel caso generale; di solito è veloce almeno quanto una semplice ricerca (su documenti di dimensioni minime; su documenti più piccoli di questo non importerebbe poiché anche se è più lento, è ancora abbastanza veloce).


1

È plausibile che in alcuni linguaggi di alto livello (forse javascript), l'uso di una libreria regex implementata in un linguaggio di basso livello (forse C) sarebbe più veloce della scrittura della logica parser nel linguaggio di alto livello.

Plausibile - Non ho idea se questo sia mai realmente il caso.


Ben fatto! Questo è qualcosa che anch'io ho considerato. Ma con i processori di oggi molto più veloci dei suoi predecessori, posso tranquillamente dire che se scrivi il codice in modo efficiente, raramente sarai in grado di dire il diff. In realtà, nel complesso, non sono davvero gaga sull'ipotesi più veloce dell'intera espressione regolare! ;-)
user3833732
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.