7

i know there are several questions about regex recursion in .net. I can write somewhat complex regex expressions but this recursion is beyond me, i am just not able to write it.

This are the questions closest to what i want.

first question, second question.

but it matches the entire string, i want the matches in a collection preferably the innermost match first or in some order. Also it matches on one opening character and one closing character. Mine is 2 chars for opening and closing, [! and !]

my input string will be something like this.

[!a='test' b='[!a='innertest' b='innervalue'!]'!]

I need to find the innertest section, [!a='innertest' b='innervalue'!], first and then evaluate it through one of my expression trees. then evaluate the parent one containing it.

Can anyone help with this?

Community
  • 1
  • 1
Alex J
  • 1,547
  • 2
  • 26
  • 41

1 Answers1

13

Here's a pattern that might satisfy your needs:

^\[!((?<n>\w+='\[!)|(?<inner-n>!]')|\w+='(?!\[!)[^']*'| )*!](?!(n))$

It will give the innermost item for each item in order. To explain what I mean, given the code:

[!a='test' c='[!x='blah'!]' b='[!a='[!y='innermost'!]' b='innervalue'!]' !]

It will give the following matches (in the capture collection for the group "inner"):

x='blag'
y='innermost'
a='[!y='innermost'!]' b='innervalue'

So, for each x=y item in the [! .. !], it will give the matches in order from innermost outwards.

If you also want the overall expression to be captured you can modify it like this:

^(?<n>\[!)((?<n>\w+='\[!)|(?<inner-n>!]')|\w+='(?!\[!)[^']*'| )*(?<inner-n>!])(?!(n))$

Giving:

x='blag'
y='innermost'
a='[!y='innermost'!]' b='innervalue'
a='test' c='[!x='blag'!]' b='[!a='[!y='innermost'!]' b='innervalue'!]' 

And to explain the regex:

^       # 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
porges
  • 30,133
  • 4
  • 83
  • 114
  • this looks good..Thank you for your help. i'm going to try it out. is there a way to tell the order, like innermost first, since I need to evaluate that first. – Alex J Mar 21 '12 at 23:11
  • Not directly. You could work it out by using the `Capture.Start` and `Capture.Length` properties for each capture, since that will let you know which captures contain which other captures. However, if each `x='...'` can only depend on what it contains, then this order should work fine. – porges Mar 21 '12 at 23:42
  • it is very close to what i want. thank you for your effort. You must be a genius!!! One final question on this. If I wanted to change the opening and closing tags to [} and {], instead of the [!, !], how will the |\w+='(?!\[!)[^']*'| section change. I tried a few things but wasn't capturing it. – Alex J Mar 22 '12 at 12:20
  • It will be `(?!\[\})` instead of `(?!\[!)`. Also make sure you are escaping the `{` and `}` in the other places. – porges Mar 22 '12 at 19:34