Regex - como combinar tudo, exceto um padrão específico

171

Como escrevo um regex para corresponder a qualquer sequência que não atenda a um padrão específico? Estou diante de uma situação em que tenho que corresponder a um padrão (A e ~ B).

não não
fonte
O PCRE seria o melhor para isso: consulte Regex Pattern to Match, Excluindo quando… / Exceto entre . Eu removi a findstrtag, pois todas as respostas aqui não são válidas para a tag.
Wiktor Stribiżew

Respostas:

192

Você pode usar uma afirmação antecipada:

(?!999)\d{3}

Este exemplo corresponde a três dígitos diferentes de 999.


Mas se você não possui uma implementação de expressão regular com esse recurso (consulte Comparação de sabores de expressões regulares ), provavelmente precisará criar uma expressão regular com os recursos básicos por conta própria.

Uma expressão regular compatível apenas com sintaxe básica seria:

[0-8]\d\d|\d[0-8]\d|\d\d[0-8]

Isso também corresponde a qualquer sequência de três dígitos que não seja 999.

quiabo
fonte
1
Look-ahead não é sintaxe de expressão regular padrão, é uma extensão Perl, ele só irá funcionar em Perl, PCRE (RegEx Perl-Compatible) ou outras implementações não-padrão
Juliano
10
Pode não ser padrão, mas a maioria dos idiomas modernos não suporta? Que idioma não suporta o futuro hoje em dia?
22410 Bryan Oakley
1
Isso é verdade. Porém, a maioria dos tipos de expressões regulares suporta esse recurso (consulte <expressões- regulares.info/refflavors.html> ).
Gumbo
1
Acho que a última regex também não combinaria 009, 019 ... etc
Sebastian Viereck
1
O Lex padrão para C não usa PCREs :-(
pieman72
30

Se você deseja combinar uma palavra A em uma string e não uma palavra B. Por exemplo: Se você tiver um texto:

1. I have a two pets - dog and a cat
2. I have a pet - dog

Se você deseja pesquisar linhas de texto que TÊM um cachorro para animais de estimação e NÃO têm gato, use esta expressão regular:

^(?=.*?\bdog\b)((?!cat).)*$

Ele encontrará apenas a segunda linha:

2. I have a pet - dog
Aleks
fonte
Ele falhou em mencioná-lo na pergunta, mas o OP está realmente usando o findstrcomando DOS . Ele oferece apenas um pequeno subconjunto dos recursos que você espera encontrar em uma ferramenta regex; lookahead não está entre eles. (Eu apenas acrescentou o findstr tag mim mesmo.)
Alan Moore
2
hm, sim, eu encontrei agora em um de seus comentários nas postagens. Eu vi Regex no título. De qualquer forma, se alguém encontra este post para buscar o mesmo para a expressão regular, como eu fiz, talvez ele poderia ser útil para alguém :) graças para comentários
Aleks
15

Faça a correspondência com o padrão e use o idioma do host para inverter o resultado booleano da correspondência. Isso será muito mais legível e sustentável.

Ben S
fonte
1
Então acabo com (~ A ou B) em vez de (A e ~ B). Isso não resolve o meu problema.
notnot 4/03/09
1
Pseudo-código: String toTest; if (toTest.matches (a) e toTest.matches (B)!) {...}
Ben S
Eu deveria ter sido mais claro - as peças não são totalmente independentes. Se A corresponder a parte da string, nos importamos se ~ B corresponder ao restante (mas não necessariamente a coisa toda). Isso foi para a função findstr da linha de comando do Windows, que eu achei restrita a regexs verdadeiros, portanto, ponto discutível.
notnot 4/03/09
8

não, ressuscitando essa questão antiga porque tinha uma solução simples que não foi mencionada. (Encontre sua pergunta ao fazer uma pesquisa para uma missão de recompensa regex .)

Estou diante de uma situação em que tenho que corresponder a um padrão (A e ~ B).

O regex básico para isso é assustadoramente simples: B|(A)

Você simplesmente ignora as correspondências gerais e examina as capturas do Grupo 1, que conterão A.

Um exemplo (com todas as isenções de responsabilidade sobre a análise de html no regex): A é dígitos, B é dígitos dentro <a tag

A regex: <a.*?<\/a>|(\d+)

Demonstração (veja o Grupo 1 no painel inferior direito)

Referência

Como combinar o padrão, exceto nas situações s1, s2, s3

Como combinar um padrão, a menos que ...

zx81
fonte
Isso parece bom demais para ser verdade! Infelizmente, esta solução não é universal e falha no Emacs, mesmo após a substituição \dpor [[:digit:]]. A primeira referência menciona que é específico para Perl e PHP: "Há uma variação usando sintaxe específica para Perl e PHP que realiza o mesmo."
Miguelmorin
4

O complemento de um idioma comum também é um idioma comum, mas para construí-lo, é necessário criar o DFA para o idioma comum e transformar qualquer estado válido em erro. Veja isso para um exemplo. O que a página não diz é que ele convertido /(ac|bd)/em /(a[^c]?|b[^d]?|[^ab])/. A conversão de um DFA de volta para uma expressão regular não é trivial. É mais fácil se você puder usar a expressão regular inalterada e alterar a semântica no código, como sugerido anteriormente.

Juliano
fonte
2
Se eu estivesse lidando com regexs reais, tudo isso seria discutível. O Regex agora parece se referir ao espaço nebuloso CSG-ish (?) De correspondência de padrões que a maioria dos idiomas suporta. Como preciso combinar (A e ~ B), não há como remover a negação e ainda fazer tudo em uma única etapa.
notnot 4/03/09
O Lookahead, como descrito acima, teria feito isso se o findstr fizesse algo além dos reais regexs do DFA. A coisa toda é meio estranha e não sei por que tenho que fazer esse estilo de linha de comando (lote agora). É apenas mais um exemplo de minhas mãos sendo amarradas.
notnot 4/03/09
1
@notnot: você está usando o findstr do Windows? Então você só precisa de / v. Como: findstr A arquivo de entrada | findstr / v B> outputfile.txt O primeiro corresponde a todas as linhas com A, o segundo corresponde a todas as linhas que não possuem B.
Juliano
Obrigado! Isso é exatamente o que eu precisava. Eu não fiz a pergunta dessa maneira, no entanto, continuo dando a resposta a Gumbo para uma resposta mais generalizada.
notnot 5/03/09
1

padrão - re

str.split(/re/g) 

retornará tudo, exceto o padrão.

Teste aqui

unigogo
fonte
Você provavelmente quer mencionar que precisa participar novamente.
26412 tomdemuyt
Uma abordagem semelhante está sendo usada replace str.replace(/re/g, ''), então não há necessidade de se juntar a eles. Além disso, se você jogar uma boa trilha? como str.replace(/\re\s?/g, '')então você se livra de todos os espaços duplicados que você teria de algo sendo substituído no meio de uma cadeia de caracteres
jakecraige
0

Minha resposta aqui também pode resolver seu problema:

https://stackoverflow.com/a/27967674/543814

  • Em vez de Substituir, você usaria Match.
  • Em vez de grupo $1, você leu grupo $2.
  • O grupo $2foi feito sem captura lá, o que você evitaria.

Exemplo:

Regex.Match("50% of 50% is 25%", "(\d+\%)|(.+?)");

O primeiro grupo de captura especifica o padrão que você deseja evitar. O último grupo de captura captura todo o resto. Simplesmente leia esse grupo $2,.

Timo
fonte
0
(B)|(A)

depois use o que o grupo 2 captura ...

DW.
fonte
Ele precisa capturar não B, seu objetivo não é apenas ignorar todos os padrões B.
Hexicle