Conheça seus sabores regex
Há uma quantidade surpreendente de pessoas que pensam que expressões regulares são essencialmente independentes da linguagem. No entanto, existem diferenças bastante substanciais entre os sabores e, especialmente para o código de golfe, é bom conhecer alguns deles e seus recursos interessantes, para que você possa escolher o melhor para cada tarefa. Aqui está uma visão geral de vários sabores importantes e o que os diferencia dos outros. (Esta lista não pode realmente estar completa, mas deixe-me saber se eu perdi algo realmente flagrante.)
Perl e PCRE
Estou jogando isso em um único pote, pois não estou muito familiarizado com o sabor Perl e eles são basicamente equivalentes (PCRE é para expressões regulares compatíveis com Perl, afinal). A principal vantagem do sabor Perl é que você pode realmente chamar o código Perl de dentro do regex e da substituição.
- Recursão / sub-rotinas . Provavelmente a característica mais importante para o golfe (que só existe em alguns sabores).
- Padrões condicionais
(?(group)yes|no)
.
- Suportes mudar de caso no texto de substituição com
\l
, \u
, \L
e \U
.
- O PCRE permite alternância em lookbehinds, onde cada alternativa pode ter um comprimento diferente (mas fixo). (A maioria dos sabores, incluindo Perl, exige que os lookbehinds tenham um comprimento fixo geral.)
\G
para ancorar uma partida no final da partida anterior.
\K
para redefinir o início da partida
- O PCRE suporta propriedades de caracteres Unicode e scripts .
\Q...\E
para escapar de séries mais longas de caracteres. Útil quando você está tentando combinar uma string que contém muitos meta-caracteres.
.LÍQUIDO
Este é provavelmente o sabor mais poderoso, com muito poucas deficiências.
Uma falha importante em termos de golfe é que ele não suporta quantificadores possessivos como alguns outros sabores. Em vez de .?+
ter que escrever (?>.?)
.
Java
- Devido a um erro (consulte o Apêndice), Java suporta um tipo limitado de lookbehind de comprimento variável: você pode olhar por trás até o início da string,
.*
de onde você pode iniciar uma lookahead, como (?<=(?=lookahead).*)
.
- Suporta união e interseção de classes de caracteres.
- Possui o suporte mais amplo para Unicode, com classes de caracteres para "scripts Unicode, blocos, categorias e propriedades binárias" .
\Q...\E
como no Perl / PCRE.
Rubi
Nas versões recentes, esse sabor é igualmente poderoso como o PCRE, incluindo o suporte para chamadas de sub-rotina. Como Java, também suporta união e interseção de classes de caracteres. Um recurso especial é a classe de caracteres interna para dígitos hexadecimais: \h
(e negada \H
).
O recurso mais útil para jogar golfe é como Ruby lida com quantificadores. Mais notavelmente, é possível aninhar quantificadores sem parênteses. .{5,7}+
funciona e o mesmo acontece .{3}?
. Além disso, ao contrário da maioria dos outros sabores, se o limite inferior de um quantificador for, 0
ele pode ser omitido, por exemplo, .{,5}
é equivalente a .{0,5}
.
Quanto à sub-rotinas, a principal diferença entre sub-rotinas de PCRE e sub-rotinas de Ruby, é que a sintaxe de Ruby é um byte mais (?n)
vs \g<n>
, mas sub-rotinas de Ruby pode ser usado para capturar, enquanto PCRE redefine capturas após uma sub-rotina acabamentos.
Finalmente, Ruby possui semânticas diferentes para modificadores relacionados à linha do que a maioria dos outros tipos. O modificador que geralmente é chamado m
em outros sabores está sempre ativado no Ruby. Assim, ^
e $
sempre coincidir com o início eo fim de uma linha e não apenas o início e fim da cadeia. Isso pode economizar um byte se você precisar desse comportamento, mas custará bytes extras se não precisar, porque você precisará substituir ^
e $
por \A
e \z
, respectivamente. Além disso, o modificador que normalmente é chamado s
(que faz .
corresponder os feeds de linha) é chamado m
no Ruby. Isso não afeta a contagem de bytes, mas deve-se ter em mente para evitar confusão.
Python
O Python tem um sabor sólido, mas não conheço nenhum recurso particularmente útil que você não encontraria em nenhum outro lugar.
No entanto , há um sabor alternativo que se destina a substituir o re
módulo em algum momento e que contém muitos recursos interessantes. Além de adicionar suporte para recursão, lookbehinds de comprimento variável e operadores de combinação de classes de caracteres, ele também possui o recurso exclusivo de correspondência difusa . Em essência, você pode especificar vários erros (inserções, exclusões, substituições) que são permitidos, e o mecanismo também fornecerá correspondências aproximadas.
ECMAScript
O sabor do ECMAScript é muito limitado e, portanto, raramente é muito útil para jogar golfe. A única coisa que ele tem a oferecer é a classe de caracteres vazios negada[^]
para corresponder a qualquer caractere, bem como a classe de caracteres vazios com falha incondicional []
(ao contrário do habitual (?!)
). Infelizmente, o sabor não possui nenhum recurso que o torne útil para problemas normais.
Lua
Lua tem seu próprio sabor bastante único, que é bastante limitado (por exemplo, você não pode nem quantificar grupos), mas vem com um punhado de recursos úteis e interessantes.
- Possui um grande número de atalhos para classes de caracteres incorporadas , incluindo pontuação, caracteres maiúsculos / minúsculos e dígitos hexadecimais.
- Com
%b
ele, suporta uma sintaxe muito compacta para corresponder a cadeias equilibradas. Por exemplo, %b()
corresponde a (
e então tudo até uma correspondência )
(pulando corretamente os pares correspondentes internos). (
e )
pode haver dois caracteres aqui.
Impulso
O sabor regex do Boost é essencialmente do Perl. No entanto, possui alguns recursos novos e agradáveis para a substituição de expressões regulares, incluindo alterações de casos e condicionais . O último é exclusivo do Boost, até onde eu sei.