Como funciona?
Dê uma olhada na teoria dos autômatos
Em resumo, cada expressão regular possui um autômato finito equivalente e pode ser compilado e otimizado para um autômato finito. Os algoritmos envolvidos podem ser encontrados em muitos livros do compilador. Esses algoritmos são usados por programas unix como awk e grep.
No entanto, a maioria das linguagens de programação modernas (Perl, Python, Ruby, Java (e linguagens baseadas em JVM), C #) não usam essa abordagem. Eles usam uma abordagem de retorno recursivo, que compila uma expressão regular em uma árvore ou uma sequência de construções que representam vários sub-blocos da expressão regular. A maioria das sintaxes modernas de "expressão regular" oferece referências externas que estão fora do grupo de linguagens regulares (elas não têm representação em autômatos finitos), que são trivialmente implementáveis na abordagem de retorno recursivo.
A otimização geralmente produz uma máquina de estado mais eficiente. Por exemplo: considere aaaab | aaaac | aaaad, um programador normal pode obter a implementação de pesquisa simples, mas menos eficiente (comparando três strings separadamente) em dez minutos; mas percebendo que é equivalente a aaaa [bcd], uma pesquisa melhor pode ser feita pesquisando os quatro primeiros 'a' e testando o quinto caractere contra [b, c, d]. O processo de otimização foi um dos meus trabalhos domésticos de compilador há muitos anos, portanto, presumo que ele também esteja nos mais modernos mecanismos de expressão regular.
Por outro lado, as máquinas de estado têm alguma vantagem quando aceitam cadeias porque usam mais espaço em comparação com uma "implementação trivial". Considere um programa para remover as aspas das seqüências de caracteres SQL, ou seja: 1) inicia e termina com aspas simples; 2) aspas simples são escapadas por duas aspas simples consecutivas. Portanto: input ['a' ''] deve produzir saída [a ']. Com uma máquina de estados, as aspas simples consecutivas são tratadas por dois estados. Esses dois estados servem ao propósito de lembrar o histórico de entrada, de modo que cada caractere de entrada seja processado exatamente apenas uma vez, conforme ilustrado a seguir:
...
S1->'->S2
S1->*->S1, output *, * can be any other character
S2->'->S1, output '
S2->*->END, end the current string
Portanto, na minha opinião, a expressão regular pode ser mais lenta em alguns casos triviais, mas geralmente mais rápida do que um algoritmo de pesquisa criado manualmente, considerando o fato de que a otimização não pode ser feita com segurança por humanos.
(Mesmo em casos triviais, como pesquisar uma cadeia, um mecanismo inteligente pode reconhecer o caminho único no mapa de estados e reduzir essa parte a uma comparação simples de cadeias e evitar o gerenciamento de estados.)
Um mecanismo específico de uma estrutura / biblioteca pode ser lento porque o mecanismo faz várias outras coisas que um programador geralmente não precisa. Exemplo: a classe Regex no .NET cria vários objetos, incluindo Correspondência, Grupos e Capturas.