Regex para corresponder a um dígito duas ou quatro vezes

95

É uma pergunta simples sobre expressões regulares, mas não estou encontrando a resposta.

Quero determinar se um número aparece em sequência exatamente duas ou quatro vezes. Que sintaxe posso usar?

\d{what goes here?}

Tentei \d{2,4}, mas essa expressão também aceita três dígitos.

Renato Dinhani
fonte
Por exemplo, para corresponder a um de dois ou quatro dígitos ano .
DavidRR
O que você quer que aconteça com a string if abc 123 xyz? Deve corresponder 12porque são exatamente dois dígitos em sequência? Ou não deveria, porque 12faz parte de uma sequência de dígitos maior 123que não tem 2 nem 4? Se eu tivesse que adivinhar, acho que você deseja o último comportamento, mas sua pergunta não fica clara. Exemplos e / ou uma especificação mais clara ajudariam. Mesma pergunta para abc 12345 def... o que deve acontecer lá?
Jean-François Corbett

Respostas:

144

Não há sintaxe específica para isso, mas existem várias maneiras de fazer isso:

(?:\d{4}|\d{2})    <-- alternation: four digits or two
\d{2}(?:\d{2})?    <-- two digits, and optionally two more
(?:\d{2}){1,2}     <-- two digits, times one or two
Ruakh
fonte
1
Pessoalmente, só pensei na \d{2}(?:\d{2})?solução logo de cara - ótima variedade delas - a última, em particular, parecendo muito boa e escalável.
Nightfirecat
3
+1 por estar atento à ordem necessária ao usar a alternância para corresponder a 4 dígitos primeiro, depois 2 dígitos. Também é um bom trabalho fornecendo as outras variações.
Ahmad Mageed
9
Para qualquer um que, como eu, não entendeu o uso (?:disso, inicia um "grupo de não captura" (um grupo que não se destina a ser referenciado em uma instrução de substituição). Você também pode usar apenas parênteses, mas eles criarão um grupo de captura. Mais detalhes aqui: stackoverflow.com/questions/3512471/non-capturing-group
Jeremy Moritz
Eles mostrarão o mesmo resultado para "333" e "33"
Dan
1
@Dan: essas regexes não correspondem à string completa "333". Você pode estar usando a funcionalidade "localizar substring correspondente" da biblioteca regex por engano, em vez da funcionalidade "verificar se a string completa corresponde". Você deve consultar sua documentação.
ruakh
3
(?<!\d)(\d{2}|\d{4})(?!\d)

Esta é a maneira correta de fazer isso. A resposta aceita está errada.

Ele corresponderia a 3 dígitos (ou 5). Então, isso está errado aos meus olhos .

1) Verifique se não há nenhum dígito antes de uma sequência de 2 ou 4 dígitos, ou após uma sequência de dois ou quatro dígitos.

  • (<!) a sintaxe é negativa para trás

  • (?!) a sintaxe é antecipação negativa.

O anterior funcionaria para mid string:

Se a seqüência de pesquisa não tem conteúdo em torno dele você poderia usar o ^e $começar e terminar de âncoras de corda:

^\d{4}$|^\d{2}$
JGFMK
fonte
1
Eu não diria que a resposta aceita está errada. Eu diria que a pergunta não é clara e que essa resposta aborda uma interpretação válida dela. Sua resposta aborda outra interpretação válida (que eu acho mais provável - mas aparentemente o autor da pergunta não ...).
Jean-François Corbett
2
"Teria 3 dígitos" não é muito preciso. Acho que você quer dizer "Isso corresponderia a uma subsequência de 2 dígitos de uma sequência de 3 dígitos".
Jean-François Corbett
1
Além disso, sua resposta não funciona como o esperado em sequências de 5 ou mais dígitos . Não sou nenhum especialista em regex, mas acho que uma maneira de corrigir isso é fazer com que o lookahead / behind negativo se aplique a ambos os casos (sequências de 2 e 4 dígitos):(?<!\d)(\d{2}|\d{4})(?!\d)
Jean-François Corbett
Acho que você está correto sobre os 5 dígitos. Obrigado por essa correção. Vou consertar isso.
JGFMK
^\d{4}$|^\d{2}$seria uma forma potencial de consertar isso. Como faria^\d{2}(?!\d)|^\d{4}(?!\d)
JGFMK