У нежадного квантификатора есть стоимость, потому что каждый раз, когда он читает символ, он должен сверяться с концом шаблона.
В приведенном выше шаблоне каждый раз .
в (.+?)
соответствует, он проверяет соответствие следующих символов [Closing]
.Каждый раз, когда это происходит, и оно не совпадает, оно должно возвращаться назад и продолжать поиск.Вот почему использовался предел возврата.
Шаблон можно переписать так:
'\[Opening\]([^\[]*(?:\[(?!Closing)[^\[]*)*)(*SKIP)\[Closing\]'si
Давайте разберем этот шаблон по частям, чтобы понять его.
1) Открываем с \[Opening\]
.Этот шаблон соответствует открывающему тегу.
2) Поскольку наш шаблон не повторяется внутри себя, директива ()(*SKIP)
используется в качестве дальнейшей оптимизации.Это означает, что если мы не соответствуем шаблону, то мы возобновим наш поиск с конца того места, где мы искали.Поведение по умолчанию снова начинает поиск следующего символа.
Чтобы лучше это понять, представьте, что наша строка - sometimes we get [Close to matching
.Когда мы добираемся до [
, мы сканируем [Clos
, прежде чем решим, что на самом деле это не тот шаблон, который нам нужен.Обычно мы возвращаемся, а затем снова начинаем смотреть на Close
.Тем не менее, (*SKIP)
позволяет нам продолжать поиск на e to matc
.
3) Внутри скобок мы начинаем с шаблона [^\[]*
, который позволяет нам сопоставить столько символов, сколько мы можем, но не [
.^
означает, что нет, \[
для [
, а []
окружает его как набор символов.*
позволяет повторять столько раз, сколько возможно.
4) Теперь у нас есть (?:)*
.()
позволяет нам указать строку, а ?:
указывает, что она не будет сохранена, а *
позволяет повторять ее столько раз, сколько мы захотим (в том числе вообще без).
5) Первый символ в этой строке - \[
или просто [
, который мы ожидаем как часть нашего закрывающего тега.
6) Далее у нас есть (?!Closing\])
.(?!)
является негативным прогнозом .Предварительный просмотр означает, что синтаксический анализатор будет смотреть на следующие символы и либо совпадать, либо не совпадать без использования символов.Это позволяет нам сопоставлять что-либо, пока оно не Closing]
, фактически не потребляя его.
7) У нас есть еще один [^\[]*
, который позволяет нам продолжать есть символы после того, как мы не смогли заглянуть в будущее.Это позволяет нам продолжать использовать строку после того, как мы получим что-то вроде [Clos
.
8) Наконец, наше регулярное выражение заканчивается на \[Closing\]
.