How to Parse Repeated Name-Value Pairs using Regex in C#

Viewed 111

I am trying to parse key/value token strings out of text using Regex in C#. For example, given the string:

stuff{token1:param1}stuff{token2}stuff{token3:param3}stuff

I would end out with three capture groups:

(key=token1,value=param1)
(key=token2,value=(null))
(key=token3,value=param3)

My problem isn't writing a regular expression to do the parsing, my problem is grouping together the keys and values.

Here's the code I have so far. ("tokenPattern" is split out just to make the regular expression a bit less overwhelming.)

var text = "{token1:param1}stuff{token2}more stuff{token3:param3}";
var tokenPattern = @"(?<token>[{](?<key>[^:}]*)([:](?<value>[^}]*))?[}])";
var pattern = @"([^{]*" + tokenPattern + ")*.*?";
var match = Regex.Match(text, pattern);

The match is successful, and the the resulting Groups of interest in the "match" variable are:

? match.Groups["token"].Captures
Count = 3
    [0]: {{token1:param1}}
    [1]: {{token2}}
    [2]: {{token3:param3}}
? match.Groups["key"].Captures
Count = 3
    [0]: {token1}
    [1]: {token2}
    [2]: {token3}
? match.Groups["value"].Captures
Count = 2
    [0]: {param1}
    [1]: {param3}

Because the "value" portion of my tokens are optional, I can't find a way to match up "key"s with "value"s. I could, I suppose, re-parse each the "token" captures but that seems a bit of a pain.

Is there a way to drill into a "token" capture to find the associated "key" and "value" (if any) for that specific capture?

1 Answers

You can use a simpler pattern to match all pattern occurrences in the string using Regex.Matches - all the necessary strings will already be grouped:

var text = "{token1:param1}stuff{token2}more stuff{token3:param3}";
var pattern = @"\{(?<key>[^:}]*)(?::(?<value>[^}]*))?}";
var matches = Regex.Matches(text, pattern);
foreach (Match m in matches)
{
    Console.WriteLine(m.Value);
    Console.WriteLine(m.Groups["key"].Value);
    Console.WriteLine(m.Groups["value"].Value);
}

See the C# demo and the regex demo. \{(?<key>[^:}]*)(?::(?<value>[^}]*))?} matches

  • \{ - a { char
  • (?<key>[^:}]*) - Group "key": zero or more chars other than : and }
  • (?::(?<value>[^}]*))? - an optional non-capturing group matching : and then Group "value" matching zero or more chars other than }
  • } - a } char.
Related