Регулярное выражение не подбирает среднюю группу

Регулярное выражение (PHP):

"/\b(screen|front|glass|lcd)\b.*?\b(not)?\b.*?\b(replaced|cracked|broken|chipped)\b/i"

Цель состоит в том, чтобы регулярное выражение совпадало с обоими:

"screen is not cracked"
"screen is cracked"

и возьмите НЕ, если присутствует как вторая группа. Однако, похоже, что вторая группа пуста для обоих приведенных выше примеров ввода.

Что я делаю неправильно?

Совет: я проверяю это с помощью http://www.regexe.com/

3 ответа

Решение

Вы можете поместить первый не жадный квантификатор в необязательную группу со словом "not":

\b(screen|front|glass|lcd)\b(?:.*?\b(not)\b)?.*?\b(replaced|cracked|broken|chipped)\b

Так \b(not)\b больше не является необязательным внутри группы без захвата, и не жадный квантификатор выполняет свою работу и останавливается, когда достигается "not".

Оптимизированный способ, который лениво захватывает слова до тех пор, пока они не будут взломаны / разбиты / заменены / сломаны и, в конечном итоге, поймут "не":

\b(screen|front|glass|lcd)\W+(?>(?:(not)|\w+)\W+)*?(?=[crb])(c(?:racked|hipped)|replaced|broken)\b

Так как .*? перед шаблоном, который соответствует необязательному, также не будет соответствовать not жадно. В этом случае вам нужно использовать негативную перспективу.

(screen|front|glass|lcd)(?:(?!\bnot\b).)*(not)?.*?(replaced|cracked|broken|chipped)

(?:(?!\bnot\b).)* будет проверять совпадение символа, не будет начальной буквой в строке not, Если да, то он будет соответствовать следующему символу. Иначе, он не будет соответствовать следующему символу, что приведет к пустому совпадению (из-за*).

DEMO

Ты забыл слово "есть"

m!\b(screen|front|glass|lcd)\b *is *\b(not\b)?(replaced|cracked|broken|chipped)\b!i
Другие вопросы по тегам