ArsenalRocks
ArsenalRocks

Reputation: 339

Regex to match between custom text

This is giving me a hard time. I have an expression like this: isnull(Num([abc]), [a], [b]) + sum([d])

I am trying to get everything that is enclosed within square brackets which is inside the isnull(). So from the above example, I should get [abc], [a] and [b] but not [d].

I have come up with this - isnull\((?:\[)(.*?)(?:\]) which gives me only [abc] but not [a] and [b].

What can I change in my regex pattern so that I get the correct matches? I am using VS2019 and C# if it matters.

Upvotes: 2

Views: 209

Answers (1)

Wiktor Stribiżew
Wiktor Stribiżew

Reputation: 626802

You can use

(?i)\bisnull\((?>[^][()]|(?<x>\[[^][]*])|(?<o>)\(|(?<-o>)\))*(?(o)(?!))\)

See the regex demo. Details:

  • (?i) - case insensitive matching enabled
  • \b - a word boundary
  • isnull\( - isnull( text
  • (?>[^][()]|(?<x>\[[^][]*])|(?<o>)\(|(?<-o>)\))* - either any char other than ], [, ( and ], or a [...] substring captured into Group "x", or a ( and an empty value is pushed onto Group "o" capture stack, or a ) and an empty value is popped from Group "o" capture stack, repeat zero or more times
  • (?(o)(?!)) - if Group "o" capture stack is not empty, fail the current match
  • \) - ) char.

See a C# demo:

var pattern = @"\bisnull\((?>[^][()]|(?<x>\[[^][]*])|(?<o>)\(|(?<-o>)\))*(?(o)(?!))\)";
var text = "isnull(Num([abc]), [a], [b]) + sum([d])";
var result = Regex.Matches(text, pattern, RegexOptions.IgnoreCase)
                  .Cast<Match>().Select(p => p.Groups["x"].Captures)
                  .ToList();
foreach (var coll in result)
    foreach (var v in coll)
        Console.WriteLine(v);
// => [abc], [a], [b]

Or, if you are after a single match:

var result = Regex.Match(text, pattern, RegexOptions.IgnoreCase)?.Groups["x"].Captures;
Console.WriteLine(string.Join(", ", result)); // => [abc], [a], [b]

See this C# demo.

Upvotes: 4

Related Questions