Estou tentando escrever um regex que exibirá todas as palavras com 10 caracteres e nenhuma das letras esteja repetindo.
Até agora, eu tenho
grep --colour -Eow '(\w{10})'
Qual é a primeira parte da pergunta. Como eu verificaria a "singularidade"? Realmente não tenho idéia, além disso, preciso usar referências anteriores.
grep
regular-expression
Dylan Meeus
fonte
fonte
Respostas:
exclui palavras que possuem dois caracteres idênticos.
exclui aqueles que têm caracteres repetidos.
POSIXly:
tr
coloca as palavras em sua própria linha, convertendo qualquer sequivalência de caracteres que não sejam palavras ( complemento de alfanumérico e sublinhado) em um caractere de nova linha.Ou com um
grep
:(exclua linhas com menos de 10 e mais de 10 caracteres e aquelas com um caractere aparecendo pelo menos duas vezes).
Com
grep
apenas um (GNU grep com suporte para PCRE oupcregrep
):Ou seja, um limite de palavras (
\b
) seguido por uma sequência de 10 caracteres de palavras (desde que cada um não seja seguido por uma sequência de caracteres de palavras e por si mesmos, usando o operador PCRE negativo antecipado(?!...)
).Temos sorte que ele funcione aqui, já que muitos mecanismos de regexp não funcionam com referências anteriores em peças repetidas.
Note que (com minha versão do GNU grep pelo menos)
Não funciona, mas
faz (as
echo aa | grep -Pw '(.)\2'
) que soa como um bug.Você pode querer:
se você quiser
\w
ou\b
considerar qualquer letra como um componente de palavra e não apenas as letras ASCII em códigos de idioma não ASCII.Outra alternativa:
Esse é um limite de palavras (aquele que não é seguido por uma sequência de caracteres de palavras, uma das quais se repete), seguido por 10 caracteres de palavras.
Coisas que você pode ter no fundo da mente:
Babylonish
distinção entre maiúsculas e minúsculas, portanto, por exemplo, haveria correspondência, pois todos os caracteres são diferentes, mesmo que existam doisB
s, um menor e outro maiúsculo (use-i
para mudar isso).-w
,\w
e\b
, uma palavra é uma letra (ASCII apenas para GNUgrep
por enquanto , a[:alpha:]
classe de caracteres em sua localidade, se estiver usando-P
e(*UCP)
), dígitos decimais ou sublinhado .c'est
(duas palavras conforme a definição francesa de uma palavra) ouit's
(uma palavra de acordo com algumas definições em inglês de uma palavra) ourendez-vous
(uma palavra conforme a definição de palavra francesa) não são consideradas uma palavra.(*UCP)
combinação de caracteres Unicode, não são considerados componentes de palavras, portantotéléphone
($'t\u00e9le\u0301phone'
) é considerado com 10 caracteres, um dos quais não alfa.défavorisé
($'d\u00e9favorise\u0301'
) seria correspondido mesmo que tenha dois,é
porque são 10 caracteres alfa diferentes, seguidos por um sotaque agudo combinado (não alfa, portanto, há um limite de palavras entre oe
e o sotaque).fonte
\w
não corresponde-
embora.Ok ... aqui está a maneira desajeitada para uma sequência de cinco caracteres:
Como você não pode colocar uma referência anterior em uma classe de personagem (por exemplo
[^\1|\2]
), você deve usar um olhar negativo à frente -(?!foo)
. Esse é um recurso PCRE, portanto você precisa da-P
troca.O padrão para uma sequência de 10 caracteres será muito mais longo, é claro, mas há um método mais curto usando um comprimento variável de qualquer coisa correspondente ('. *') No cabeçalho:
Depois de ler a resposta esclarecedora de Stephane Chazelas, percebi que existe um padrão simples semelhante para esse utilizável através do
-v
switch grep :Como a verificação prossegue com um caractere de cada vez, isso indica se algum caractere é seguido por zero ou mais caracteres (
.*
) e, em seguida, corresponde à referência anterior.-v
inverte, imprimindo apenas coisas que não correspondem a esse padrão. Isso torna as referências anteriores mais úteis, pois não podem ser negadas com uma classe de personagem e significativamente:trabalhará para identificar uma sequência de qualquer tamanho com caracteres exclusivos, enquanto:
não corresponderá, pois corresponderá qualquer sufixo a caracteres únicos (por exemplo,
abcabc
correspondências por causa deabc
no final eaaaa
por causa dea
no final - portanto, qualquer string). Essa é uma complicação causada pelo fato de as lookarounds terem largura zero (elas não consomem nada).fonte
(.)(?!.*\1)(.)(?!.*\2)(.)(?!.*\3)(.)(?!\4).
Se você não precisar fazer a coisa toda no regex, eu o faria em duas etapas: primeiro corresponda a todas as palavras de 10 letras e depois filtre-as por exclusividade. A maneira mais curta de saber como fazer isso é no Perl:
Observe as
\W
âncoras adicionais para garantir que apenas as palavras com exatamente 10 caracteres sejam correspondidas.fonte
Outros sugeriram que isso não é possível sem várias extensões para certos sistemas de expressão regular que na verdade não são regulares. No entanto, como o idioma que você deseja corresponder é finito, é claramente regular. Para 3 letras de um alfabeto de 4 letras, seria fácil:
Obviamente, isso sai do controle às pressas com mais letras e alfabetos maiores. :-)
fonte
A opção
--perl-regexp
(curta-P
) do GNUgrep
usa expressões regulares mais poderosas que incluem padrões de antecipação. O padrão a seguir procura cada letra que esta letra não apareça no restante da palavra:No entanto, o comportamento em tempo de execução é bastante ruim, porque
\w*
pode ter um tamanho quase infinito. Pode ser limitado a\w{,8}
, mas isso também verifica além do limite de palavras de 10 letras. Portanto, o seguinte padrão verifica primeiro o tamanho correto da palavra:Como arquivo de teste, usei um arquivo grande de 500 MB:
Atualizar:
Não consegui encontrar uma alteração significativa no comportamento em tempo de execução para um operador não ganancioso (
\w*?
) ou operador possessivo ((...){10}+
). Um pouquinho mais rápido parece a substituição da opção-w
:Uma atualização do grep da versão 2.13 para 2.18 foi muito mais eficaz. O arquivo de teste levou apenas 6 segundos.
fonte
\w{,8}?
) ajudava em algum tipo de entrada (embora não muito significativamente). Bom uso\g{-1}
para solucionar o bug do GNU grep.\g{-1}
, porque torna o padrão mais independente da localização. Nesta forma, ele pode ser usado como parte de um padrão maior.Uma solução Perl:
mas não funciona com
ou
testado com perl v5.14.2 e v5.18.2
fonte