У меня есть следующий RegEx, который используется и работает:
/\B@(@?\w+(?:::\w+)?)([ \t]*)(\( ( (?>[^()]+) | (?3) )* \))?/x
Где эта строка @extends('template', 'test')
правильно группирует и дает мне то, что мне нужно.
Проблема в том, что если строка содержит незакрытые скобки внутри кавычек — это не удастся:
@extends('template', 'te)st')
дает @extends('template', 'te)
в качестве выхода
Как я могу сказать этому RegEx игнорировать круглые скобки, которые находятся внутри кавычек (либо '
или же "
)
Вот демонстрация проблемы RegExr: http://regexr.com/v1?396ci
И вот список строк, которые все должны быть в состоянии передать:
@extends('template', 'test') // working
@extends('template', $test) // working
@extends('template', 'te()st') // working
@extends('template', 'te)st') // broken
@extends('template', 'te())st') // broken
@extends('template', 'te(st') // broken
@extends('template', 'test)') // broken
@extends('template', '(test') // broken
Я сузил это — и я думаю, что я должен быть в состоянии сказать
(
\( <-- only if not inside quotes
(
(?>[^()]+) | (?3)
)*
\) <-- only if not inside quotes
)?
Но я не могу понять, как применить это правило к этим конкретным скобкам
Вы можете использовать Lookahead для этой цели
Вот мое регулярное выражение, которое будет соответствовать второму аргументу всех extends
(? = (\ Ш +) | \ ш + ()) [\ ш) (] +
Сломать:
'
: Начать поиск строки с кавычки
?=XXX)
: Позитивный взгляд вперед, обеспечивающий присутствие XXX впереди
(\w+\)|\w+\()
: Поиск открывающих или закрывающих скобок
Теперь, если этот взгляд был успешным, мы можем быть уверены, что у нас есть кавычка, за которой следует скобка. Теперь мы можем просто написать регулярное выражение, чтобы сделать скобки
[\w\)\(]+
: Просто так
Теперь, когда мы можем найти кавычки с круглыми скобками внутри, мы можем использовать условие if-else, чтобы использовать соответствующие правила для каждого случая
(?(?=regex)then|else)
Вот как я это реализовал:
(?(?='(?=(\w+\)|\w+\())) <- condition, same as above
'[\w\)\(]+' <- We have a match so we ignore parenthesis
|'\w+' <- Here we don't
)
пс. Я многое не понял из того, что вы написали для другой части вашего регулярного выражения, возможно, это касается некоторых других случаев, поэтому я не пишу, чтобы изменить исходное регулярное выражение. Вы можете просто переключить проверку для второго параметра с упомянутым выше
Вот мое регулярное выражение, которое соответствует всем вашим случаям.
\B@\w+\('[\w+\s]+',\s+(?(?='(?=(\w+\)|\w+\()))'[\w\)\(]+'|('\w+'|\$\w+))\)
Вы можете увидеть тестовые случаи Вот
PS. Чтобы показать, что это действительно работает, я добавил несколько неудачных тестов.
Других решений пока нет …