Jak dopasować, ale nie uchwycić, część wyrażenia regularnego?


209

Mam listę ciągów. Niektóre z nich mają formę 123-...456. Część zmienna „...” może być:

  • ciąg „jabłko”, po którym następuje myślnik, np 123-apple-456
  • ciąg „banan”, po którym następuje myślnik, np 123-banana-456
  • pusty ciąg znaków, np. 123-456(pamiętaj, że jest tylko jeden łącznik)

Każde słowo inne niż „jabłko” lub „banan” jest nieprawidłowe.

W tych trzech przypadkach chciałbym dopasować odpowiednio „jabłko”, „banan” i „”. Pamiętaj, że nigdy nie chcę przechwytywać łącznika, ale zawsze chcę go dopasować . Jeśli ciąg nie ma takiej postaci, 123-...456jak opisano powyżej, to w ogóle nie ma zgodności.

Jak napisać wyrażenie regularne, aby to zrobić? Załóżmy, że mam smak, który pozwala grupom patrzeć naprzód, patrzeć za siebie, patrzeć i nie przechwytywać.


Kluczową obserwacją jest to, że gdy masz „jabłko” lub „banan”, musisz także mieć łącznik końcowy, ale nie chcesz go dopasowywać. A kiedy jesteś dopasowanie pusty ciąg, to nie muszą mieć łącznik z tyłu. Myślę, że wyrażenie regularne, które zawiera to twierdzenie, będzie właściwe.


Chcesz dopasować wszystko oprócz łączników?
BrunoLM,

Odpowiedzi:


285

Jedynym sposobem, aby czegoś nie uchwycić, jest zastosowanie rozeznania :

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

Ponieważ nawet w przypadku grup nie przechwytujących(?:…) całe wyrażenie regularne przechwytuje ich dopasowaną treść. Ale to wyrażenie regularne dopasowuje tylko applelub bananajeśli jest poprzedzony 123-oraz zakończony -456, albo dopasowuje pusty łańcuch, jeśli jest poprzedzony 123-oraz zakończony 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 - W tym przypadku możesz obejść ten problem, używając grupy 1 zamiast grupy 0, ale jest to doskonałe (i subtelne!) Rozróżnienie.
Ben Blank

@Ben Blank: Z pewnością zależy to od interpretacji „dopasowania” i „przechwytywania”.
Gumbo,

8
Nie są obsługiwane w JavaScript, yay ! byłoby miło mieć przyjazną dla JS metodę, ale wcale nie złą, +0,5 (zaokrąglanie w górę; D)
GiantCowFilms

Uwielbiam twierdzenia dookoła! Działa to doskonale również z Ruby.
Rots

idealne rozwiązanie, uwielbiam to
Trần Quang Hiệp

15

Aktualizacja: Dzięki Germán Rodríguez Herrera!

W javascript spróbuj: /123-(apple(?=-)|banana(?=-)|(?!-))-?456/

Pamiętaj, że wynik znajduje się w grupie 1

Demo Debuggex


8

Próbować:

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

To będzie pasować apple, bananalub pusty ciąg, a po nim pojawią się łączniki 0 lub 1. Myliłem się, nie potrzebując grupy przechwytującej. Głupi ja.


Nie jest to poprawne, ponieważ pasuje na przykład do „123-coconut-456”.
David Stone

Myślałem, że chcesz to bardziej ogólne ... naprawione.
Thomas

5

Zmodyfikowałem jedną z odpowiedzi (autor: @ op1ekun):

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

Powodem jest to, że odpowiedź z @ op1ekun również pasuje "123-apple456", bez łącznika po jabłku.


3

Spróbuj tego:

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

1
Nie jest to poprawne, ponieważ pasuje na przykład do „123-coconut-456”.
David Stone

@ David: czym to się różni od twojego przykładu z bananem?
SilentGhost,

@SilentGhost: Ja tylko chcę chwytania applelub bananalub „”. Wszystkie inne wartości są nieprawidłowe, jak już powiedziałem.
David Stone

sry, w takim przypadku: / \ d {3} - (? :( apple | banana) -)? \ d {3} /
slosd

1
Ten przykład pokazuje, że możliwe jest posiadanie grupy nieprzechwycącej bez użycia funkcji lookahead i lookbehind.
Vince Panuccio,

0

Odmiana wyrażenia @Gumbo, która wykorzystuje \Kdo resetowania pozycji dopasowania, aby zapobiec włączeniu bloków liczbowych do dopasowania. Można go używać w smakach regularnych PCRE.

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

Mecze:

Match 1  apple
Match 2  banana
Match 3

-3

Zdecydowanie najprostszy (działa dla Pythona) jest '123-(apple|banana)-?456'.


1
To by pasowało, 123-apple456więc nie jest poprawne.
Loren,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.