tags:

views:

91

answers:

1

Hey,

I've been learning regular expressions for the last few days and I've been stumbled on this one. I would like to split a string by commas but with exceptions. Here's my string on what I want to validate:

rp { av 100, re 3, 52 }

which is basic comma delimited values inside of curly braces. Getting the values, I can do. But inside of each values, there could be another

rp { values, values values }

which I don't want it to catch. This can be recursive.


String to evaluate:

rp { av 100, re 3, rp { value 1, value 2, value 3 }, 52 }

Desired match:

av 100
re 3
rp { value 1, value 2, value 3 }
52

I need your help on this one. Thanks, community.

+2  A: 

It's not clear to me if this example represents a potential infinite nesting of these JSON-esque groups, or just one level of nesting.

If only one level of nesting is possible, a straightforward Regex will do:

(Please note I did not write this with an IDE; the concept should be correct but syntax errors can't be guaranteed at the moment. Apologies)

string pattern = @"(?<key>)[A-Z]+)\s(?<value>({.+?}|[^{},]+))";

List<string[]> results = new List<string[]>(); //probably not best data structure

MatchCollection matches = Regex.Matches(input, pattern, RegexOptions.SingleLine | RegexOptions.IgnoreCase);
foreach(Match match in matches)
{
    if(match.Success)
    {
        results.Add(new string[] {
            match.Groups["key"].Value,
            match.Groups["value"].Value
        });
    }
}

If they can be nested many levels, you probably want to approach this recursively. That would necessitate splitting the value match into nested value and simple value:

string pattern = @"(?<key>)[A-Z]+)\s({(?<nested>.+?)}|(?<simple>[^{},]+))";

And for each match where nested has a value, execute the same routine against that value:

void Deserialize(string input, List<string[]> values)
{
    MatchCollection matches = Regex.Matches(input, pattern, RegexOptions.SingleLine | RegexOptions.IgnoreCase);
    foreach(Match match in matches)
    {
        if(match.Success)
        {
            if(match.Groups["nested"].Success && !string.IsNullOrEmpty(match.Groups["nested"].Value))
            {
                Deserialize(match.Groups["nested"].Value, values);
            }
            else
            {
                values.Add(new string[] {
                    match.Groups["key"].Value,
                    match.Groups["simple"].Value
                });
            }
        }
    }
}
Rex M
Yes, approaching this recursively is what I was shooting for. I will edit my post and I will try your example. I have never used recursive regex before.
AlexDemers
@Alex please see my answer revisions.
Rex M
Your answers are most highly prized, Sir ! best,
BillW
I got the concept. Thanks for the help, much appreciated.
AlexDemers