Pergunta

À procura de um pouco de ajuda regex. Eu gostaria de criar uma expressão que corresponde a uma string com " foo " ou " bar ", mas não ambos " foo " E " bar "

Se eu fizer algo como ...

/((foo)|(bar))/

Ele vai corresponder " foobar ". Não o que eu estou procurando. Então, como posso fazer match regex somente quando um termo ou o outro está presente?

Obrigado!

Foi útil?

Solução

Você pode fazer isso com um único regex mas eu sugiro que por uma questão de legibilidade você faz algo como ...

(/foo/ and not /bar/) || (/bar/ and not /foo/)

Outras dicas

Isto é o que eu uso:

/^(foo|bar){1}$/

Veja: http://www.regular-expressions.info/quickstart.html sob repetição

Se os seus suportes de linguagem regex-lo, use negativo Lookaround :

(?<!foo|bar)(foo|bar)(?!foo|bar)

Isso irá corresponder "foo" ou "bar" que não é imediatamente precedido ou seguido por "foo" ou "bar", que eu acho que é o que você queria.

Não é claro da sua pergunta ou exemplos se a corda que você está tentando jogo pode conter outros símbolos: "foocuzbar". Se assim for, este padrão não vai funcionar.

Aqui estão os resultados de seus casos de teste ( "true" significa que o padrão foi encontrado na entrada):

foo: true
bar: true
foofoo: false
barfoo: false
foobarfoo: false
barbar: false
barfoofoo: false

Isso vai levar 'foo' e 'bar', mas não 'foobar' e não 'blafoo' e não 'blabar':

/^(foo|bar)$/

^ = mark start of string (or line)
$ = mark end of string (or line)

Isso vai levar 'foo' e 'bar' e 'bar foo' e 'bar-foo', mas não 'foobar' e não 'blafoo' e não 'blabar':

/\b(foo|bar)\b/

\b = mark word boundry

Você não especificou comportamento em relação ao outro conteúdo do "foo" e "bar" ou repetições de um, na ausência do outro. por exemplo, deveria " foo d" ou " barbar ian" jogo?

Assumindo que você deseja corresponder cordas que contêm apenas uma instância de qualquer "foo" ou "bar", mas não ambos, e não várias instâncias do mesmo, sem levar em conta para qualquer outra coisa na cadeia (ou seja, "comida "partidas 'bárbaro' não corresponde), então você pode usar uma expressão regular que retorna o número de registro de jogos e apenas considerá-lo bem sucedido se exatamente uma correspondência for encontrada. por exemplo, em Perl:

@matches = ($value =~ /(foo|bar)/g)  # @matches now hold all foos or bars present
if (scalar @matches == 1) {          # exactly one match found
  ...
}

Se várias repetições de que mesmo alvo são permitidos (ou seja, partidas "bárbaras"), então esta mesma abordagem geral poderia ser usado por, em seguida, caminhando a lista de jogos para ver se os jogos são todas as repetições do mesmo texto ou se a outra opção também está presente.

Você pode querer considerar o? teste condicional.

(?(?=regex)then|else)

Expressões Regulares Conditionals

Se você quer um verdadeiro exclusivo ou, eu tinha acabado de fazer isso no código em vez de na regex. Em Perl:

/foo/ xor /bar/

Mas o seu comentário:

Jogos: "foo", "bar" nonmatches: "Foofoo" "barfoo" "foobarfoo" "barbar" "Barfoofoo"

indica que você não está realmente procurando exclusivo ou. Você realmente significa "Match /foo|bar/ faz exatamente uma vez?"

my $matches = 0;
while (/foo|bar/g) {
  last if ++$matches > 1;
}

my $ok = ($matches == 1)

Eu sei que isto é uma entrada tardia, mas apenas para ajudar outras pessoas que podem estar procurando:

(/b(?:(?:(?!foo)bar)|(?:(?!bar)foo))/b)

Eu usaria algo como isto. Ele verifica apenas para o espaço em torno das palavras, mas você poderia usar o \b ou \B para verificar se há uma fronteira, se você usa \w. Isso iria corresponder "foo" ou "bar", então obviamente você tem que substituir o espaço em branco, bem como, apenas no caso. (Supondo que você está substituindo nada.)

/\s((foo)|(bar))\s/

Eu não acho que isso pode ser feito com uma única expressão regular. E limites pode ou não funcionar, dependendo do que você está combinando contra.

Eu jogo contra cada regex separadamente, e fazer um XOR sobre os resultados.

foo = re.search("foo", str) != None
bar = re.search("bar", str) != None
if foo ^ bar:
    # do someting...

Eu tentei com Regex treinador contra:

x foo y
x bar y
x foobar y

Se eu marque a opção g, na verdade, corresponde a todas as três palavras, porque ele procura novamente após cada jogo.
Se você não quiser esse comportamento, você pode ancorar a expressão, por exemplo correspondência somente em limites de palavra:

\b(foo|bar)\b

Dar mais contexto sobre o problema (o que os olhares de dados como) pode dar melhores respostas.

\b(foo)\b|\b(bar)\b

e utilizar apenas o primeiro grupo de captura .

Usando os limites de palavra, você pode obter a palavra única ...

me@home ~  
$ echo "Where is my bar of soap?" | egrep "\bfoo\b|\bbar\b"  
Where is my bar of soap?  

me@home ~  
$ echo "What the foo happened here?" | egrep "\bfoo\b|\bbar\b"  
What the foo happened here?  

me@home ~  
$ echo "Boy, that sure is foobar\!" | egrep "\bfoo\b|\bbar\b"  
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top