Соответствие регулярному выражению, если в строке есть только одно совпадение из нескольких вариантов - PullRequest
2 голосов
/ 16 июня 2020

Есть ли шаблон для поиска, если есть только одно совпадение из нескольких вариантов в строке?

Допустим, у нас есть следующий список возможных совпадений:

`foo|bar|baz`

И у нас есть строки:

`Foo bar, Cambaz!` // shoud not match due to multiple findings
`My bar, good!` // shoud match for `bar`
`My friend, Cambaz!` // shoud match for baz

без учета регистра.

Ответы [ 3 ]

4 голосов
/ 16 июня 2020

Используйте

(?i)^(?:(?!foo|bar|baz).)*\K(?:foo|bar|baz)(?!.*(?:foo|bar|baz))

См. proof .

Сопоставьте текст, который не соответствует ни одной из альтернатив до первого совпадения (^(?:(?!foo|bar|baz).)*), опустить совпавший текст (\K), сопоставить слово из списка ((?:foo|bar|baz)), а затем проверить, нет ли слова из списка позже в тексте ((?!.*(?:foo|bar|baz))).

(?i) - без учета регистра.

Укороченная версия с подпрограммами :

(?i)^(?:(?!(foo|bar|baz)).)*\K\g<1>(?!.*\g<1>)

См. другое подтверждение

\g<1> обозначает узор (foo|bar|baz).

2 голосов
/ 16 июня 2020

Вы можете использовать это регулярное выражение PCRE:

^(?>.*?(foo|bar|baz)){2}.*(*SKIP)(*F)|(?1)

RegEx Demo

  • (*F) или (*FAIL) глагол ведет себя как неудачное отрицательное утверждение и является синонимом для (?!)
  • (*SKIP) и определяет точку, за которой механизму регулярных выражений не разрешается возвращаться назад, когда подшаблон не работает позже.
  • Идея трюка (*SKIP)(*FAIL) для использования символов, которых вы хотите избежать, и которые не должны быть частью результата сопоставления.
  • (?1): рекурсирует 1-й подшаблон
1 голос
/ 17 июня 2020

Вы также можете использовать (*COMMIT), чтобы прервать дальнейшие исследования, когда подшаблон после (здесь предварительный просмотр) не работает:

(foo|bar|baz)(*COMMIT)(?!.*(?1))

демонстрация

...