Як співставити частину регулярних виразів, але не захопити їх?


209

У мене є список рядків. Деякі з них мають форму 123-...456. Частина змінної "..." може бути:

  • рядок "яблуко" з наступним дефісом, напр 123-apple-456
  • рядок "банан" з наступним дефісом, напр 123-banana-456
  • пустий рядок, наприклад 123-456(зауважте, що є лише один дефіс)

Будь-яке слово, крім "яблуко" або "банан", недійсне.

У цих трьох випадках я хотів би відповідати "яблуко", "банан" і "" відповідно. Зауважте, що я ніколи не хочу захоплювати дефіс, але завжди хочу відповідати йому. Якщо рядок не має такої форми, 123-...456як описано вище, то це взагалі не відповідає.

Як написати регулярний вираз для цього? Припустимо, у мене є аромат, який дозволяє шукати групи, дивлячись позаду, шукати навколо та не захоплювати групи.


Основне зауваження тут полягає в тому, що коли у вас є або "яблуко", або "банан", ви також повинні мати дефіс, але не хочете його відповідати. І коли ви співпадаєте з порожнім рядком, у вас не повинно бути дефісу. Я думаю, що правильний вираз, який інкапсулює це твердження, буде правильним.


Ви хочете зіставити все, крім дефісів?
BrunoLM

Відповіді:


285

Єдиний спосіб не зафіксувати щось - це використання тверджень навколо .

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

Тому що навіть із групами,(?:…) що не захоплюють, весь регулярний вираз фіксує їх відповідність вмісту. Але це регулярний вираз відповідає тільки appleабо bananaякщо він передує 123-і потім -456, або відповідає порожній рядку , якщо вона передує 123-і слід 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 - У цьому випадку можна обійти це, скориставшись групою 1, а не групою 0, але це відмінна (і тонка!) Відмінність.
Бен Бланк

@Ben Blank: Це, безумовно, залежить від того, як інтерпретуються "матч" та "захоплення".
Гумбо

8
Чи не підтримується в JavaScript, яй ! було б добре мати метод дружнього JS, але зовсім не погано, +0,5 (округлюючи; D)
GiantCowFilms

Любовні зауваження! Вони також чудово працюють з Рубі.
Rots

ідеальне рішення, я люблю це
Trần Quang Hiệp


8

Спробуйте:

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

Це буде відповідати apple, bananaабо порожній рядок, і після його там буде 0 або 1 дефіс. Я помилявся, що не мав потреби в захопленні групи. Дурний мене.


Це неправильно, оскільки відповідає, наприклад, "123-кокосовому горіху-456".
Девід Стоун

Думав, що ти хочеш цього більш загального ... виправлено
Томас

5

Я змінив одну з відповідей (від @ op1ekun):

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

Причина в тому, що відповідь від @ op1ekun також відповідає "123-apple456", без дефісу після яблука.


3

Спробуйте це:

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

1
Це неправильно, оскільки відповідає, наприклад, "123-кокосовому горіху-456".
Девід Стоун

@david: чим це відрізняється від прикладу вашого "банана"?
SilentGhost

@SilentGhost: Я тільки хочу , щоб захопити appleабо bananaабо «». Як я вже зазначив, усі інші значення є недійсними.
Девід Стоун

sry, у такому випадку: / \ d {3} - (? :( яблуко | банан) -)? \ d {3} /
slosd

1
Цей приклад показує, що можна створити групу, яка не захоплює, не використовуючи lookahead та озираючись.
Вінс Пануччо

0

Варіант виразу від @Gumbo, який використовує \Kдля скидання позицій матчу, щоб запобігти включенню числових блоків у відповідність. Використовується в ароматах регексу PCRE.

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

Матчі:

Match 1  apple
Match 2  banana
Match 3

-3

На сьогодні найпростіший (працює для python) '123-(apple|banana)-?456'.


1
Це збігається, 123-apple456тому це невірно.
Лорен
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.