Expressões regulares que funcionam “em qualquer lugar”
(johndcook.com)- Expressões regulares têm diferenças de recursos e sintaxe conforme a implementação, então um padrão que funciona em uma ferramenta pode falhar ou exigir ajustes em outro ambiente
- Quanto mais você estiver acostumado a ambientes ricos em recursos, como Perl, mais frequentemente encontrará problemas de compatibilidade; considerando até computadores nos quais não há permissão para instalar nada, é mais seguro usar um subconjunto comum
- Se definirmos “em qualquer lugar” da forma mais rigorosa possível, o escopo fica tão estreito que restam apenas literais, classes de caracteres
[…]e metacaracteres básicos como. * ^ $ - Se você usar GNU
sed,awkegrep, junto com a opção-Eemsedegrep, o conjunto de recursos em comum utilizável fica maior, mas nessa combinação oawkacaba sendo, em geral, o menor denominador comum - No Emacs,
+? ( ) { } |exigem barra invertida, e\se\Stambém têm significados diferentes; para reutilizar a mesma expressão regular em várias ferramentas, é preciso verificar até a sintaxe de exceção
Por que a compatibilidade de expressões regulares é difícil
- O maior incômodo das expressões regulares vem das diferenças entre implementações
- Um recurso suportado por uma ferramenta pode simplesmente não existir em outra
- Mesmo quando o recurso existe, a sintaxe pode variar um pouco
- Perl é um ambiente de expressões regulares muito rico em recursos, então funcionalidades que parecem óbvias sob a ótica do Perl podem estar ausentes em outros ambientes
- Também dá para usar substitutos parecidos com Perl em outras ferramentas, mas como isso não é padronizado, fica difícil enviar código que rode imediatamente para colegas ou clientes
- Considerando até situações em que você precisa trabalhar em computadores onde não é possível instalar software, torna-se necessário buscar um subconjunto de recursos de expressões regulares que funcione em vários ambientes
- Quanto mais rígida for a definição de “em qualquer lugar”, menos recursos poderão ser usados
- literais
- classes de caracteres
[…] - caracteres especiais
. * ^ $
Faixa comum entre sed, awk, grep e Emacs
- Se limitarmos as ferramentas-alvo a
sed,awk,grepe Emacs, dá para afrouxar um pouco o critério de “em qualquer lugar” - Se você usar as versões GNU de
sed,awkegrep, e aplicar a opção-Eemsedegrep, a lista de recursos em comum aumenta- Os recursos de expressões regulares das três ferramentas são parecidos
- Os recursos do
awkem geral também são suportados pelas outras ferramentas - Como exceção, limite de palavra em
awkusa\<e\>, diferentemente de\be\B
- O Emacs corresponde à maior parte dos recursos do
awk, mas há diferenças de sintaxe- Para
+ ? ( ) { } |terem o mesmo papel que emawk, é preciso colocar uma barra invertida antes - As expressões correspondentes a
\se\Sdoawksão\s-e\S-no Emacs
- Para
- No Emacs,
\se\Snão significam espaço/não-espaço, e sim o início de uma classe de caracteres- A classe
-significa espaço em branco \s.representa caractere de pontuação\S.representa caractere que não é de pontuação
- A classe
- Com esse critério, os recursos utilizáveis são os seguintes
.^,$[…],[^…]*\w,\W,\s,\S- Referências retroativas de
\1até\9 \b,\B?,+- alternativa
| - repetição
{n,m} - captura
(...)
- Porém, o
gawkoferece suporte a referências retroativas em strings de substituição, mas não na própria expressão regular look-aroundpode ser visto como um recurso avançado, e\dpode parecer um recurso básico para dígitos, mas muitos dialetos de expressões regulares não o suportam
1 comentários
Opiniões no Hacker News
No Emacs, é especialmente sofrido porque parece quase um chute descobrir o que precisa ser escapado
Existe uma alternativa chamada
rx[0], mas, na prática, não é algo prazeroso de usarPara além da própria sintaxe de expressões regulares, problemas de codificação e escaping também aparecem com frequência na etapa de uso real
Ao digitar uma regex no shell, é preciso escapá-la corretamente; em Python, é preciso verificar se é uma string bruta (raw string), e assim por diante
Mesmo assim, o fato de a forma de usar expressões regulares na maioria das ferramentas ter convergido para algo dentro de uma faixa relativamente parecida é quase um milagre moderno
[0]: https://www.gnu.org/software/emacs/manual/html_node/elisp/Rx...
Situações em que diferentes regras de escaping ficam sobrepostas continuam aparecendo
(e)sejam correspondidos literalmenteO autor parece quase chegar lá, mas, no fim, acho que quer dizer que expressões regulares básicas POSIX funcionam em qualquer lugar
Só com a ressalva de que nem todo mundo acompanhou a 8ª edição da Single Unix Specification, e que nessa edição as BRE mudaram um pouco
Sem essa ressalva, nem haveria motivo para escrever o texto em primeiro lugar
Há algum tempo escrevi um artigo procurando expressões regulares que casam da mesma forma tanto com semântica gulosa quanto com semântica leftmost maximal
https://par.nsf.gov/servlets/purl/10534654
Sempre fui exigente quanto a deixar claro qual linguagem de expressões regulares uma ferramenta aceita e se ela casa uma substring arbitrária, um prefixo, um sufixo, a string inteira, uma linha ou uma substring dentro de uma linha
Entre elas estão [as mais usadas][1], além de PCRE e Python
Levei um tempo para aprender que algumas das formas antigas vistas em lugares como o grep [estão especificadas no POSIX][2]
[1]: https://cppreference.com/cpp/regex#Regular_expression_gramma...
[2]: https://pubs.opengroup.org/onlinepubs/009696899/basedefs/xbd...
Quero compartilhar as páginas de Russ Cox sobre expressões regulares
Considero uma boa leitura
https://swtch.com/~rsc/regexp/
É por motivos como esse que o RFC 9485, I-Regexp: An Interoperable Regular Expression Format, é importante
https://datatracker.ietf.org/doc/html/rfc9485
O pacote regexp da biblioteca padrão do Go usa o motor RE2, por isso não dá suporte a retroreferências
Elas podem ser usadas em substituições, mas não em matching
regexpnão usa re2; é uma implementação separada dos mesmos conceitosDepois de passar por frustrações parecidas com motores de regras, motores de templates e motores do tipo IFTTT, criei uma biblioteca Rust para JSONLogic e também uso bindings para outras linguagens
https://github.com/GoPlasmatic/datalogic-rs
A documentação do JSON Schema também tem um subconjunto de expressões regulares recomendado
https://json-schema.org/understanding-json-schema/reference/...