Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Regex: match everything inside closest opening and closing curly braces around expression

Tags:

c#

.net

regex

It's a bit hard to explain what I really want (better title suggestions are appreciated so people can find this easily in the future).

Suppose I have this:

{
    {
        $myTagThing$
    }
}

I want to match

{
    $myTagThing$
} 

i.e. match everything from the last { before $myTagThing$ until the first } after $myTagThing$.

So I thought I'd need this \{.*\$myTagThing\$.*\}, but it will also match the first { and last } in the string (i.e. the whole example). Then I tried using a lookahead and a lookbehind (both negative) \{(.*(?!\{))\$myTagThing\$.*(?<!\})\}(https://regex101.com/r/RfdHUH/1/). But this still doesn't work.

My theory is that I might be using lookahead and lookbehind the wrong way since this is the first time I use them.

Any ideas?

EDIT: flags are \gms.

like image 410
ItsaMeTuni Avatar asked Sep 21 '18 03:09

ItsaMeTuni


2 Answers

NOTE This was upvoted 3 times and marked as the accepted answer for revision 2 of this question, before the question was changed to a different scenario, and this answer was unaccepted.

You need to look for: opening-curly-brace, then a sequence of characters which are not open or close-curly-brace, then close-curly-brace.

Specifically: {[^{}]*}

like image 108
Richardissimo Avatar answered Nov 18 '22 21:11

Richardissimo


EDIT: This addresses a { $myTagThing$ {} } scenario no longer included in question.

Regarding your updated question. What you want, in .NET, is called balanced groups. In other regex engines, balanced constructs/expressions. The terminology slightly varies, the syntax is wildly different between engines, and so is the behavior.

Anyway, to capture the largest {} contents possible, you want:

[^{}]*
(
((?'Open'{)[^{}]*)+
((?'Close-Open'})[^{}]*)+
)*
(?(Open)(?!))

(Set the ignore whitespace flag or collapse this regex). This is the core of your answer. We just modify it with the first and last line here:

\{[^{}]*myTagThing
[^{}]*
(
((?'Open'{)[^{}]*)+
((?'Close-Open'})[^{}]*)+
)*
(?(Open)(?!))
[^{}]*\}

regex storm

The "one regex" solution can get complicated fast, but if you find yourself using .NET regexes often, you might find the following worth looking into:

Searching for specific text inside balanced chars (recursive

The link above is where I had an issue where I was looking for a string like:

Type VAR.*while{{VAR++}} where the while could be followed by balanced {}. The bounty-awarded answer is the one you want to look at. It's a more complicated problem than yours, but you can see that it gets insane pretty quick:

Also see the official documentation on this feature:

https://learn.microsoft.com/en-us/dotnet/standard/base-types/grouping-constructs-in-regular-expressions#balancing_group_definition

like image 26
zzxyz Avatar answered Nov 18 '22 19:11

zzxyz