Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Simplest way to construct a string by interpolating values into a Regex pattern?

I usually end up with a lot of conditions and/or loops to parse a regex and interpolate values back into its capture groups, and am looking for experienced answers to solve this problem in hopefully a simple manner.

For example, given a regex pattern like X(?<xid>\d+)-(?<xsub>\w+)\.xml having the named capture groups "xid" and "xsub", intended to match filenames like: X1-foo.xml, X555-bar.xml, etc, when provided with the arguments: int xid=999, string xsub="baz", I want to interpolate those values into the pattern groups to construct the proper filename: X999-baz.xml

To keep it simple, explicit captures are not nested.


Without String.Format:

This concept is easily accomplished with .NET String format items like String.Format("X{0}-{1}.xml", xid, xsub) however I already have a Regex pattern to parse out those values from any filename string, and want to use the same pattern to go in the opposite direction by reconstructing a filename with it, for accuracy. If I require a regex pattern to parse values from a string, but a string with format items to reconstruct the filename, it requires two kinds of distinct syntaxes to be used, creating a greater chance of manual error when writing them - it's too easy to mistakenly create a bad format item string that does not properly reconstruct the result of a regex pattern match, or vice versa.

like image 560
John K Avatar asked Nov 05 '22 14:11

John K


1 Answers

You can use regex (yay, meta-regexes!):

public static string RegexInterp(Regex pattern, Dictionary<string, string> pairs) {
    string regex = pattern.ToString();
    string search;

    foreach(KeyValuePair<string, string> entry in pairs) 
    {
        // using negative lookbehind so it doesn't match escaped parens
        search = @"\(\?<" + entry.Key + @">.*?(?<!\\)\)"; 
        regex  = Regex.Replace(regex, search, entry.Value);
    }

    return Regex.Unescape(unescaped);
}

And then:

Regex rx = new Regex(@"X(?<xid>\d\d+)-(?<xsub>\w+)\.xml");

var values = new Dictionary <string, string>() {{"xid", "999"},
                                                {"xsub", "baz"}} ;

Console.WriteLine(RegexInterp(rx, values));     

Prints

X999-baz.xml

Demo: http://ideone.com/QwI2W

like image 197
NullUserException Avatar answered Nov 09 '22 17:11

NullUserException