Чтобы захватить весь блок IF / ENDIF со сбалансированными операторами IF, вы можете использовать это регулярное выражение:
%IF\s+(?<Name>\w+)
(?<Contents>
(?> #Possessive group, so . will not match IF/ENDIF
\s|
(?<IF>%IF)| #for IF, push
(?<-IF>%ENDIF)| #for ENDIF, pop
. # or, anything else, but don't allow
)+
(?(IF)(?!)) #fail on extra open IFs
) #/Contents
%ENDIF
Суть в следующем: вы не можете захватить в одной Match
больше, чем одну из каждой названной группы. Вы получите только одну (?<Name>\w+)
группу, например, из последнего захваченного значения. В своем регулярном выражении я сохранил группы Name
и Contents
вашего простого регулярного выражения и ограничил балансировку внутри группы Contents
- регулярное выражение по-прежнему заключено в IF
и ENDIF
.
Если становится интересно, когда ваши данные более сложны. Например:
%IF MY_VAR
some text
%IF OTHER_VAR
some other text
%ENDIF
%IF OTHER_VAR2
some other text 2
%ENDIF
%ENDIF
%IF OTHER_VAR3
some other text 3
%ENDIF
Здесь вы получите два матча: один для MY_VAR
, а другой для OTHER_VAR3
. Если вы хотите захватить два if в содержимом MY_VAR
, вам нужно перезапустить регулярное выражение для его группы Contents
(вы можете обойти его, если воспользуетесь предвидением, если вам нужно - оберните все регулярное выражение в (?=...)
, но вам нужно как-то поместить его в логическую структуру, используя позиции и длины).
Теперь я не буду слишком много объяснять, потому что кажется, что вы получаете основы, но короткое примечание о группе содержимого - я использую притяжательную группу, чтобы избежать возврата назад. В противном случае точка могла бы в конечном итоге соответствовать целым IF
с и нарушить баланс. Ленивый матч в группе будет вести себя аналогично (( )+?
вместо (?> )+
).