Corresponde a tudo, exceto para strings especificadas

118

Eu sei que a seguinte regex corresponderá a "vermelho", "verde" ou "azul".

red|green|blue

Existe uma maneira simples de fazer com que corresponda a tudo, exceto várias strings especificadas?

Alfred
fonte
1
Nem todos os tipos de expressões regulares podem fazer isso. Em que ambiente você está trabalhando? Java? Perl? .INTERNET? Alguma biblioteca regex C / C ++? Um RDBMS?
FrustratedWithFormsDesigner
8
Você não diz o que deseja, mas pode simplesmente inverter o sentido da operação de "correspondência". Isso não ajudará se você estiver tentando fazer extração nas partes não correspondentes, mas para testar se uma string excluída não está presente, funcionaria: if (!s.match(/red|green|blue/)) ... Nota: eu sei que o OP não especifica qual linguagem / estrutura, então o anterior deve ser considerado um exemplo genérico, não prescritivo.
tvanfosson

Respostas:

153

Se você quiser ter certeza de que o barbante não é vermelho, verde ou azul, a resposta de caskey é esta. O que geralmente se deseja, no entanto, é certificar-se de que a linha não contenha vermelho, verde ou azul em qualquer lugar dela. Para isso, ancore a expressão regular com ^e inclua .*na antevisão negativa:

^(?!.*(red|green|blue))

Além disso, suponha que você queira linhas contendo a palavra "motor", mas sem nenhuma dessas cores:

^(?!.*(red|green|blue)).*engine

Você pode pensar que pode fatorar o .*para o início da expressão regular:

^.*(?!red|green|blue)engine     # Does not work

Mas você não pode. Você precisa ter as duas instâncias de .*para que funcione.

Wayne Conrad
fonte
48

Depende do idioma, mas geralmente existem afirmações negativas que você pode colocar assim:

(?!red|green|blue)

(Obrigado pela correção de sintaxe, o acima é Java e Perl válidos, YMMV)

Caskey
fonte
2
@caskey, A resposta completa é uma combinação minha e sua. Se você quiser mesclá-los, excluirei o meu.
Wayne Conrad,
13
Essa resposta seria muito mais útil se você a explicasse um pouco. Por exemplo: O que fazer "?" e "!" significar? Por que você precisa de grupos de captura?
Lii
É Python válido também.
Joe Mornin
apenas usei isso com a biblioteca Delphi regEx e só funciona assim: ^ (?! vermelho | verde | azul). Também é válido para testá-lo em regex101.com . Portanto, o erro de digitação acima está faltando um ^ ou realmente funciona assim em Java / Perl / Python ..?
Peter
32

Combinando qualquer coisa, exceto strings fornecidas

Se você deseja combinar toda a string onde deseja combinar tudo, mas certas strings, você pode fazer assim:

^(?!(red|green|blue)$).*$

Isso diz, comece a correspondência do início da string onde ela não pode começar e terminar com vermelho, verde ou azul e corresponder a qualquer outra coisa ao final da string.

Você pode tentar aqui: https://regex101.com/r/rMbYHz/2

Observe que isso só funciona com mecanismos regex que suportam uma antecipação negativa .

Sam
fonte
23

Você não precisa de antecipação negativa. Há um exemplo de trabalho:

/([\s\S]*?)(red|green|blue|)/g

Descrição:

  • [\s\S] - corresponde a qualquer personagem
  • * - corresponde de 0 a ilimitado do grupo anterior
  • ? - corresponder o menos possível
  • (red|green|blue|) - corresponde a uma destas palavras ou nada
  • g - repetir padrão

Exemplo:

whiteredwhiteredgreenbluewhiteredgreenbluewhiteredgreenbluewhiteredgreenbluewhiteredgreenbluewhiteredgreenbluewhiteredgreenbluewhiteredwhiteredwhiteredwhiteredwhiteredwhiteredgreenbluewhiteredwhiteredwhiteredwhiteredwhiteredredgreenredgreenredgreenredgreenredgreenbluewhiteredbluewhiteredbluewhiteredbluewhiteredbluewhiteredwhite

Será:

whitewhitewhitewhitewhitewhitewhitewhitewhitewhitewhitewhitewhitewhitewhitewhitewhitewhitewhitewhitewhitewhitewhitewhitewhite

Teste-o: regex101.com

hlcs
fonte
4
Você pode reduzir drasticamente a contagem de passos trocando [\ s \ S] por um ponto. Fiquei muito confuso por que, aparentemente, todos os outros exemplos capturam cada palavra individualmente. Dessa forma, é um pouco mais etapas regex, mas requer muito menos pós-processamento.
Zatronium de
3
mas isso não faz correspondência (validação de texto), apenas remove o texto especificado durante a substituição.
Marek R de
Esta solução não produzirá a parte final do texto após as palavras conhecidas. Então, não há necessidade de comparar a velocidade, ela está errada.
Wiktor Stribiżew
@ WiktorStribiżew fixed.
hlcs
10

Tive a mesma dúvida, as soluções propostas estavam quase a funcionar mas apresentavam alguns problemas. No final, a regex que usei é:

^(?!red|green|blue).*

Testei em Javascript e .NET.

. * não deve ser colocado dentro do lookahead negativo como este: ^ (?!. * red | green | blue) ou faria o primeiro elemento se comportar de forma diferente do resto (ou seja, "outro vermelho" não seria correspondido enquanto " outro verde "seria)

Durden81
fonte
3

A correspondência de qualquer texto, exceto aqueles que correspondem a um padrão, geralmente é obtida com a divisão da string com o padrão regex .

Exemplos :

  • - Regex.Split(text, @"red|green|blue")ou, para se livrar de valores vazios, Regex.Split(text, @"red|green|blue").Where(x => !string.IsNullOrEmpty(x))(veja demo )
  • - Regex.Split(text, "red|green|blue")ou, para remover itens vazios, Regex.Split(text, "red|green|blue").Where(Function(s) Not String.IsNullOrWhitespace(s))(consulte a demonstração ou esta demonstração onde LINQ é compatível)
  • - text.split(/red|green|blue/)(não há necessidade de usar o gmodificador aqui!) (para se livrar dos valores vazios, use text.split(/red|green|blue/).filter(Boolean)), veja a demonstração
  • - text.split("red|green|blue"), ou - para manter todos os itens vazios - use text.split("red|green|blue", -1), ou para remover todos os itens vazios, use mais código para removê-los (veja a demonstração )
  • - Semelhante ao Java, text.split(/red|green|blue/)para fazer com que todos os itens finais sejam usados text.split(/red|green|blue/, -1)e para remover todos os itens vazios usados text.split(/red|green|blue/).findAll {it != ""})(veja demo )
  • - text.split(Regex("red|green|blue"))ou, para remover itens em branco, use text.split(Regex("red|green|blue")).filter{ !it.isBlank() }, consulte a demonstração
  • - text.split("red|green|blue"), ou para manter todos os itens vazios no final, use text.split("red|green|blue", -1)e para remover todos os itens vazios, use text.split("red|green|blue").filter(_.nonEmpty)(ver demonstração )
  • - text.split(/red|green|blue/), para se livrar de valores vazios, use .split(/red|green|blue/).reject(&:empty?)(e para obter itens vazios à esquerda e à direita, use -1como o segundo argumento .split(/red|green|blue/, -1)) (consulte a demonstração )
  • - my @result1 = split /red|green|blue/, $text;, ou com todos os itens vazios à direita my @result2 = split /red|green|blue/, $text, -1;, ou sem quaisquer itens vazios, my @result3 = grep { /\S/ } split /red|green|blue/, $text;(veja a demonstração )
  • - preg_split('~red|green|blue~', $text)ou preg_split('~red|green|blue~', $text, -1, PREG_SPLIT_NO_EMPTY)para não produzir itens vazios (ver demonstração )
  • - re.split(r'red|green|blue', text)ou, para remover itens vazios, list(filter(None, re.split(r'red|green|blue', text)))(ver demonstração )
  • - Use regexp.MustCompile("red|green|blue").Split(text, -1), e se você precisar remover itens vazios, use este código . Veja a demonstração do Go .

NOTA : Se seus padrões contiverem grupos de captura , as funções / métodos de divisão de regex podem se comportar de maneira diferente, dependendo também de opções adicionais. Consulte então a documentação do método de divisão apropriada.

Wiktor Stribiżew
fonte
0

Todos exceto a palavra "vermelho"

var href = '(text-1) (red) (text-3) (text-4) (text-5)';

var test = href.replace(/\((\b(?!red\b)[\s\S]*?)\)/g, testF); 

function testF(match, p1, p2, offset, str_full) {
  p1 = "-"+p1+"-";
  return p1;
}

console.log(test);

Todos exceto a palavra "vermelho"

var href = '(text-1) (frede) (text-3) (text-4) (text-5)';

var test = href.replace(/\(([\s\S]*?)\)/g, testF); 

function testF(match, p1, p2, offset, str_full) {
  p1 = p1.replace(/red/g, '');
  p1 = "-"+p1+"-";
  return p1;
}

console.log(test);

Юрий Светлов
fonte