Tive a impressão de que grep e awk usavam uma máquina regex NFA (não determinística).
A imagem no meio desta página sobreA correspondência de expressões regulares pode ser simples e rápidaconfirme que esse é o caso.
Sabe-se que uma implementação de NFA pode parar quando a primeira alternância for correspondida. Por exemplo, esta máquina NFA do artigo vinculadoPor exemplo, considere o NFA para abab|abbb:
O que corresponde ao regex abab|abbb
alcançará o estado correspondente à direita com a string ababbbb
ao combinar o primeiro abab
. Nesse ponto, ele irá parar quando chegar ao fim, para um estado correspondente (S10). Não há necessidade de testar mais entradas, mesmo que outra correspondência abbb
seja possível.
Ou seja, neste código:
echo 'catfish' | grep -Eo 'cat|catfish'
O resultado deveria ser, cat
mas é catfish
. Não importa se a alternância é trocada, o resultado é o mesmo.
O que faz o mecanismo grep regex sempre encontrar a correspondência mais longa?
E é possível alterar esse padrão?
Responder1
Eu não acho que exista uma maneira de fazer isso com um compatível com POSIX grep
ou awk
, porque o padrão requer a correspondência mais longa, de fato (veja, por exemplo, a regex(7)
página de manual).
Com awk
você pode obter a saída desejada modificando o awk
programa e o regexp, por exemplo
echo 'SetValue' | awk '{ if (match($0, /Set(Value)?/)) { print substr($0, RSTART, 3); }
Nessa situação, eu procuraria pcregrep
(parte da biblioteca de expressões regulares compatível com pcre Perl), que permite especificar um subgrupo numerado com -o
:
echo SetValue | pcregrep -o1 '(Set)(Value)?'
ou, porque pcre tem sintaxe para correspondência não gananciosa,
echo SetValue | pcregrep -o0 'Set(Value)??'
Responder2
Até onde pude entender isso, descobri que existem, de fato,duas máquinas NFA:
Motor NFA tradicional
Uma máquina NFA que retrocede e para a quala correspondência mais longa à esquerda nem sempre poderia ser respeitada.Mecanismo POSIX NFA
Um mecanismo NFA sem retrocesso que processa todos os estados em paralelo e pode escolher qualquer correspondência na string de entrada. A seleção da correspondência mais longa e à esquerda é um requisito do POSIX.
No entanto, uma máquina de retrocesso DFA (Perl) que podeexplodir exponencialmente (2^n)é orientado pelo texto (não pela regex) e pode selecionar o primeiro de uma alternância (ou não).
Diz-se também que umO DFA reconhece todas as correspondências possíveis em paralelo.
E, do autor do artigo vinculado na pergunta, oA implementação de re2 define alternância como: x|y ==> x ou y (prefira x), ou seja: prefira o primeiro de uma alternância.
Portanto, em conclusão, não há como realmente relacionar os AFN ou AFD com qual parte de uma alternância será selecionada, isso depende da implementação específica.
E não, não encontrei uma maneira de dizer a uma implementação específica para alterar seu padrão.
Relacionado: