Вот шаблон, который может удовлетворить ваши потребности:
^\[!((?<n>\w+='\[!)|(?<inner-n>!]')|\w+='(?!\[!)[^']*'| )*!](?!(n))$
Это даст самый внутренний элемент для каждого элемента в порядке. Чтобы объяснить, что я имею в виду, приведем код:
[!a='test' c='[!x='blah'!]' b='[!a='[!y='innermost'!]' b='innervalue'!]' !]
Это даст следующие совпадения (в коллекции перехвата для группы «внутренний»):
x='blag'
y='innermost'
a='[!y='innermost'!]' b='innervalue'
Таким образом, для каждого элемента x=y
в [! .. !]
он будет давать совпадения в порядке от самого внутреннего к внешнему виду.
Если вы также хотите, чтобы общее выражение было захвачено, вы можете изменить его следующим образом:
^(?<n>\[!)((?<n>\w+='\[!)|(?<inner-n>!]')|\w+='(?!\[!)[^']*'| )*(?<inner-n>!])(?!(n))$
Предоставление:
x='blag'
y='innermost'
a='[!y='innermost'!]' b='innervalue'
a='test' c='[!x='blag'!]' b='[!a='[!y='innermost'!]' b='innervalue'!]'
И чтобы объяснить регулярное выражение:
^ # start of string
\[! # start of overall [! .. !]
( # either ...
(?<n>\w+='\[!)| # a complex x='[! .. !]' containing a nested [! .. !] - push this onto the stack 'n'
(?<inner-n>!]')| # end of a nested [! .. !] - pop stack 'n', and capture the contents into 'inner'
\w+='(?!\[!)[^']*'| # a simple x='asdf' with no nested [! .. !]
) # or a space
* # as many times as you want
!] # the end of the overall [! .. !]
(?!(n)) # assert that the 'n' stack is empty, no mismatched [! .. !]
$ # end of string