3 pontos por GN⁺ 14 시간 전 | 1 comentários | Compartilhar no WhatsApp
  • 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, awk e grep, junto com a opção -E em sed e grep, o conjunto de recursos em comum utilizável fica maior, mas nessa combinação o awk acaba sendo, em geral, o menor denominador comum
  • No Emacs, +? ( ) { } | exigem barra invertida, e \s e \S també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, grep e Emacs, dá para afrouxar um pouco o critério de “em qualquer lugar”
  • Se você usar as versões GNU de sed, awk e grep, e aplicar a opção -E em sed e grep, a lista de recursos em comum aumenta
    • Os recursos de expressões regulares das três ferramentas são parecidos
    • Os recursos do awk em geral também são suportados pelas outras ferramentas
    • Como exceção, limite de palavra em awk usa \< e \>, diferentemente de \b e \B
  • O Emacs corresponde à maior parte dos recursos do awk, mas há diferenças de sintaxe
    • Para + ? ( ) { } | terem o mesmo papel que em awk, é preciso colocar uma barra invertida antes
    • As expressões correspondentes a \s e \S do awk são \s- e \S- no Emacs
  • No Emacs, \s e \S nã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
  • Com esse critério, os recursos utilizáveis são os seguintes
    • .
    • ^, $
    • […], [^…]
    • *
    • \w, \W, \s, \S
    • Referências retroativas de \1 até \9
    • \b, \B
    • ?, +
    • alternativa |
    • repetição {n,m}
    • captura (...)
  • Porém, o gawk oferece suporte a referências retroativas em strings de substituição, mas não na própria expressão regular
  • look-around pode ser visto como um recurso avançado, e \d pode 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 usar
    Para 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...

    • Fica ainda mais divertido quando você escreve Python que gera scripts de shell com expressões regulares
      Situações em que diferentes regras de escaping ficam sobrepostas continuam aparecendo
    • Se forçar para encontrar uma vantagem, quando o alvo da busca é código Elisp, é um pouco conveniente que ( e ) sejam correspondidos literalmente
    • Expressões regulares deveriam ter sido uma linguagem estruturada, não uma mistura de várias DSLs
  • O 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

    • Essa avaliação não me parece justa com o autor
      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

    • regexp não usa re2; é uma implementação separada dos mesmos conceitos
  • Depois 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/...