1

I am trying to wrap my head around a bug I am finding with the .Net balancing groups regex.

I am trying to match !{} as an opening/closing combination.

Current Regex -> !{[^!{}]*(((?<Open>!{)[^!{}]*)+((?<Close-Open>})[^!{}]*)+)*(?(Open)(?!))}

this matches !{some random stuff here} successfully. It also matches !{some other Stuff !{} with nesting}

However, it DOES NOT match this !{some stuff with {} just curly braces} at all. It seems the '{}' inside the string is causing some issues as it seems to think that the group is no longer "balanced"

I am testing all of this on http://regexstorm.net/tester which is a great place for .Net specific regex testing.

To be fair I am no regex expert, and have unashamedly copied / manipulated the regex from this site http://www.regular-expressions.info/balancing.html

I don't need it to be able to match nesting as I will use c# to traverse recursively into the matches, but i just need to be able to get a positive match on the example that is failing above.

UPDATE

Here is what the initial goal of the pattern is. Much like with Razor pages where it matches @{ some C# code here } as code blocks, I have used a pattern of !{some code here} to demarcate sections of code inside a html page. I have written a website for a client where they use those "replacers" to execute custom logic inside their html pages. so for example :

<p> Hello !{CurrentSession.GetUser().FirstName}</p>

When the page is rendered out I use Regex to identify those "replacers" and then use Springframework.Net to execute that code against a known context.

This has all worked brilliantly since 2009 ( yes over 10 years ago ! ) but now they are starting to use a lot more Json type data and that is where I discovered this bug / issue with my regex.

So Imagine this example

<script type="text/javascript">

 var myArray = [ !{CurrentSession.GetUser().GetDataOrDefault( '{Name:"MyName"}' )} ];

</script>

As you can see with the above example, there is Json with curly braces '{}' inside the replacer I'm trying to match !{} and that is where the regex is failing.

PS the '!' is NOT optional it MUST open with '!{' and close with '}'

thanks in advance

Mark Redfern
  • 357
  • 1
  • 3
  • 24
  • 1
    Does it mean there can be no `!` inside nested `{...}`? If it does not matter, you may just use `!{(?>[^{}]+|(?{)|(?}))*(?(Open)(?!))}` or even `!{(?>[^{}]+|(?{)|(?}))*}` – Wiktor Stribiżew Jul 06 '20 at 14:10
  • What is the meaning of curly braces without an exclamation mark? Should they still be balanced? If they should, and `!` is optional, Wiktor's solution should work for you. In such cases, one option is to introduce an escape character, for example `!{a b \{ c !{ d } }`. – Kobi Jul 06 '20 at 15:08
  • It looks like you need a dedicated code parser for that. – Wiktor Stribiżew Jul 07 '20 at 20:26
  • @WiktorStribiżew - add your comment as an answer so I can mark it as correct. I think I can use it to work through what I need, so let me give you some points as a thankyou! – Mark Redfern Jul 09 '20 at 08:21

1 Answers1

2

You may use

!{(?>[^{}]+|(?<Open>{)|(?<Close-Open>}))*}

The regex will find an exclamation mark, and then a { followed with any amount of paired nested curly braces up to the matching close brace.

See the regex demo.

Details

  • !{ - a !{ substring
  • (?>[^{}]+|(?<Open>{)|(?<Close-Open>}))* - zero or more repetitions (allowing no backtracking into the alternation atomic group) of
    • [^{}]+| - 1+ chars other than { and }, or
    • (?<Open>{)| - a { char pushed on to Group "Open" stack
    • (?<Close-Open>}) - a } char popped from Group "Open" stack saving the substring matched in Group "Close"
  • } - a } char.
Wiktor Stribiżew
  • 607,720
  • 39
  • 448
  • 563