Come abbinare, ma non catturare, parte di una regex?


210

Ho un elenco di stringhe. Alcuni di loro sono nella forma 123-...456. La parte variabile "..." può essere:

  • la stringa "mela" seguita da un trattino, ad es 123-apple-456
  • la stringa "banana" seguita da un trattino, ad es 123-banana-456
  • una stringa vuota, ad es. 123-456(nota che c'è solo un trattino)

Qualsiasi parola diversa da "mela" o "banana" non è valida.

Per questi tre casi, vorrei abbinare rispettivamente "mela", "banana" e "". Nota che non voglio mai catturare il trattino, ma voglio sempre abbinarlo . Se la stringa non ha la forma 123-...456descritta sopra, allora non c'è alcuna corrispondenza.

Come scrivo un'espressione regolare per farlo? Supponiamo che abbia un sapore che consenta lookahead, lookbehind, lookaround e gruppi non catturanti.


L'osservazione chiave qui è che quando hai "mela" o "banana", devi anche avere il trattino finale, ma non vuoi abbinarlo. E quando abbini la stringa vuota, non devi avere il trattino finale. Una regex che incapsula questa affermazione sarà quella giusta, credo.


Vuoi abbinare tutto tranne i trattini?
BrunoLM,

Risposte:


286

L'unico modo per non catturare qualcosa è usare le asserzioni look-around :

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

Perché anche con i gruppi non acquisiti(?:…) l'intera espressione regolare acquisisce i contenuti corrispondenti. Ma questa espressione regolare corrisponde solo appleo bananase è preceduta da 123-e seguita da -456, oppure corrisponde alla stringa vuota se è preceduta da 123-e seguita da 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 - In questo caso, puoi aggirare il problema utilizzando il gruppo 1 anziché il gruppo 0, ma questa è una distinzione eccellente (e sottile!).
Ben Blank,

@Ben Blank: dipende sicuramente da come vengono interpretati "match" e "capture".
Gumbo,

8
Non supportato in JavaScript, yay ! sarebbe bello avere un metodo amichevole JS, ma non è affatto male, +0.5 (arrotondamento per
eccesso

Adoro le asserzioni intorno! Funzionano benissimo anche con Ruby.
Rottura del

soluzione perfetta, adoro questo
Trần Quang Hiệp

15

Aggiornamento: grazie a Germán Rodríguez Herrera!

In javascript prova: /123-(apple(?=-)|banana(?=-)|(?!-))-?456/

Ricorda che il risultato è nel gruppo 1

Debuggex Demo


8

Provare:

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

Che corrisponderà apple, bananao una stringa vuota, e in seguito ci saranno 0 o 1 trattini. Ho sbagliato a non avere bisogno di un gruppo di cattura. Sciocco me


Ciò non è corretto poiché corrisponde, ad esempio, a "123-cocco-456".
David Stone,

Pensavo lo volessi più in generale ... riparato.
Thomas,

5

Ho modificato una delle risposte (di @ op1ekun):

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

Il motivo è che anche la risposta di @ op1ekun corrisponde "123-apple456", senza il trattino dopo apple.


3

Prova questo:

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

1
Ciò non è corretto poiché corrisponde, ad esempio, a "123-cocco-456".
David Stone,

@david: in che modo differisce dal tuo esempio di "banana"?
SilentGhost,

@SilentGhost: Ho solo voglia di cattura appleo di bananao "". Tutti gli altri valori non sono validi, come ho affermato.
David Stone,

sry, in quel caso: / \ d {3} - (? :( apple | banana) -)? \ d {3} /
slosd

1
Ciò che questo esempio mostra è che è possibile avere un gruppo che non cattura senza usare lookahead e lookbehind.
Vince Panuccio,

0

Una variante dell'espressione di @Gumbo che utilizza \Kper reimpostare le posizioni delle partite per impedire l'inclusione di blocchi numerici nella partita. Utilizzabile con regex PCRE.

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

gli incontri:

Match 1  apple
Match 2  banana
Match 3

-3

Di gran lunga il più semplice (funziona per Python) è '123-(apple|banana)-?456'.


1
Ciò corrisponderebbe 123-apple456quindi non è corretto.
Loren,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.