Como combinar, mas não capturar, parte de uma regex?


209

Eu tenho uma lista de strings. Alguns deles são da forma 123-...456. A porção variável "..." pode ser:

  • a string "apple" seguida de um hífen, por exemplo 123-apple-456
  • a cadeia "banana" seguida de um hífen, por exemplo 123-banana-456
  • uma string em branco, por exemplo 123-456(observe que há apenas um hífen)

Qualquer palavra que não seja "maçã" ou "banana" é inválida.

Para esses três casos, eu gostaria de combinar "maçã", "banana" e "", respectivamente. Observe que eu nunca quero capturar o hífen, mas sempre quero combiná- lo. Se a sequência não tiver a forma 123-...456descrita acima, não haverá correspondência.

Como escrevo uma expressão regular para fazer isso? Suponha que eu tenha um sabor que permita grupos de olhar para trás, olhar para trás, olhar em volta e não capturar.


A observação principal aqui é que, quando você tem "maçã" ou "banana", também deve ter o hífen à direita, mas não deseja correspondê-lo. E quando você estiver combinando a sequência em branco, não deverá ter o hífen à direita. Um regex que encapsula essa afirmação será o correto, eu acho.


Você quer combinar tudo, exceto hífens?
BrunoLM

Respostas:


286

A única maneira de não capturar algo é usando asserções :

(?<=123-)((apple|banana)(?=-456)|(?=456))

Porque, mesmo em grupos que não capturam,(?:…) a expressão regular inteira captura o conteúdo correspondente. Mas essa expressão regular corresponde apenas appleou bananase é precedida por 123-e seguida por -456, ou corresponde à string vazia se for precedida por 123-e seguida por 456.

|Lookaround  |    Name      |        What it Does                       |
-----------------------------------------------------------------------
|(?=foo)     |   Lookahead  | Asserts that what immediately FOLLOWS the |
|            |              |  current position in the string is foo    |
-------------------------------------------------------------------------
|(?<=foo)    |   Lookbehind | Asserts that what immediately PRECEDES the|
|            |              |  current position in the string is foo    |
-------------------------------------------------------------------------
|(?!foo)     |   Negative   | Asserts that what immediately FOLLOWS the |
|            |   Lookahead  |  current position in the string is NOT foo|
-------------------------------------------------------------------------
|(?<!foo)    |   Negative   | Asserts that what immediately PRECEDES the|
|            |   Lookbehind |  current position in the string is NOT foo|
-------------------------------------------------------------------------

1
+1 - Nesse caso, você pode contornar isso usando o grupo 1 em vez do grupo 0, mas essa é uma distinção excelente (e sutil!).
Ben Blank

@ Ben Blank: Definitivamente depende de como "match" e "capture" são interpretados.
Gumbo

8
Não suportado em JavaScript, yay ! Seria bom ter um método amigável JS, mas não é mau de todo, 0,5 (arredondamento; D)
GiantCowFilms

Adoro declarações gerais! Eles também funcionam muito bem com Ruby.
Rots

solução perfeita, eu adoro isso
Tr Qun Quang Hiệp

15

Atualização: Obrigado a Germán Rodríguez Herrera!

Em javascript tente: /123-(apple(?=-)|banana(?=-)|(?!-))-?456/

Lembre-se de que o resultado está no grupo 1

Demo de depuração


8

Experimentar:

123-(?:(apple|banana|)-|)456

Isso corresponderá a apple, bananaou uma sequência em branco e, a seguir, haverá um 0 ou 1 hífen. Eu estava errado em não ter necessidade de um grupo de captura. Parvo eu.


Isso não está correto, pois corresponde, por exemplo, "123-coconut-456".
David Stone

Achei que você queria mais geral ... fixo.
Thomas

5

Modifiquei uma das respostas (por @ op1ekun):

123-(apple(?=-)|banana(?=-)|(?!-))-?456

O motivo é que a resposta de @ op1ekun também corresponde "123-apple456", sem o hífen após a maçã.


3

Tente o seguinte:

/\d{3}-(?:(apple|banana)-)?\d{3}/

1
Isso não está correto, pois corresponde, por exemplo, "123-coconut-456".
David Stone

@ David: como isso é diferente do seu exemplo de "banana"?
SilentGhost 13/10/10

@SilentGhost: I única deseja capturar appleou bananaou "". Todos os outros valores são inválidos, como afirmei.
David Stone

sry, nesse caso: / \ d {3} - (? :( maçã | banana) -)? \ d {3} /
slosd

1
O que este exemplo mostra é que é possível ter um grupo sem captura sem usar lookahead e lookbehind.
Vince Panuccio

0

Uma variação da expressão do @Gumbo que é usada \Kpara redefinir as posições de correspondência para impedir a inclusão de blocos numéricos na correspondência. Utilizável nos sabores PCRE regex.

123-\K(?:(?:apple|banana)(?=-456)|456\K)

Partidas:

Match 1  apple
Match 2  banana
Match 3

-3

De longe, o mais simples (funciona para python) é '123-(apple|banana)-?456'.


1
Isso corresponderia, 123-apple456portanto, não está correto.
Loren
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.