How does it work?
Dai un'occhiata alla teoria degli automi
In breve, ogni espressione regolare ha un automa finito equivalente e può essere compilata e ottimizzata per un automa finito. Gli algoritmi coinvolti possono essere trovati in molti libri del compilatore. Questi algoritmi sono usati dai 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 utilizzano questo approccio. Usano un approccio di backtracking ricorsivo, che compila un'espressione regolare in un albero o una sequenza di costrutti che rappresentano vari sotto-pezzi dell'espressione regolare. Le sintassi più moderne di "espressione regolare" offrono backreferenze che sono al di fuori del gruppo di linguaggi regolari (non hanno rappresentazione in automi finiti), che sono banalmente implementabili nell'approccio ricorsivo di backtracking.
L'ottimizzazione di solito produce una macchina a stati più efficiente. Ad esempio: considerare aaaab | aaaac | aaaad, un normale programmatore può ottenere un'implementazione di ricerca semplice ma meno efficiente (confrontando tre stringhe separatamente) in soli dieci minuti; ma rendendosi conto che è equivalente aaaa [bcd], una ricerca migliore può essere eseguita cercando i primi quattro "a" e poi testando il quinto personaggio contro [b, c, d]. Il processo di ottimizzazione è stato uno dei miei lavori di compilatore a casa molti anni fa quindi presumo che sia anche nella maggior parte dei moderni motori di espressioni regolari.
D'altra parte, le macchine a stati hanno qualche vantaggio quando accettano le stringhe perché usano più spazio rispetto a una "implementazione banale". Si consideri un programma per annullare la citazione su stringhe SQL, ovvero: 1) inizia e termina con virgolette singole; 2) le virgolette singole sono sfuggite da due citazioni singole consecutive. Quindi: input ['a' ''] dovrebbe produrre output [a ']. Con una macchina a stati, le virgolette singole consecutive vengono gestite da due stati. Questi due stati hanno lo scopo di ricordare la cronologia di input in modo tale che ogni 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, a mio parere, l'espressione regolare potrebbe essere più lenta in alcuni casi banali, ma di solito più veloce di un algoritmo di ricerca manuale, dato che l'ottimizzazione non può essere eseguita in modo affidabile da umani.
(Anche in casi banali come cercare una stringa, un motore intelligente può riconoscere il singolo percorso nella mappa di stato e ridurre quella parte a un semplice confronto tra stringhe ed evitare di gestire gli stati.)
Un motore particolare da un framework / libreria può essere lento perché il motore fa un sacco di altre cose di cui un programmatore di solito non ha bisogno. Esempio: la classe Regex in .NET crea un sacco di oggetti inclusi Match, Groups e Capture.