Question

I have string which have a special substrings in a special format:

$( variableName )

And this pattern can repeat nested many times:

$( variableName $( anotherVariableName ) )

Such as: [ A test string ]

Here is a test string contain $(variableA) and $(variableB$(variableC))

For this test string Let assume that

$(variableA) = A, $(variableB) = B, $(variableC) = C, $(variableBC) = Y

What I want is replace those special patters -> $(variableName) with actual values such as the resulting string should be:

Here is a test string contain A and Y

Any suggestion for generic and elegant solution?

Was it helpful?

Solution

Here is a straightforward solution performing a recursive descent parsing:

public static string Replace(
    string input
,   ref int pos
,   IDictionary<string,string> vars
,   bool stopOnClose = false
) {
    var res = new StringBuilder();
    while (pos != input.Length) {
        switch (input[pos]) {
            case '\\':
                pos++;
                if (pos != input.Length) {
                    res.Append(input[pos++]);
                }
                break;
            case ')':
                if (stopOnClose) {
                    return res.ToString();
                }
                res.Append(')');
                pos++;
                break;
            case '$':
                pos++;
                if (pos != input.Length && input[pos] == '(') {
                    pos++;
                    var name = Replace(input, ref pos, vars, true);
                    string replacement;
                    if (vars.TryGetValue(name, out replacement)) {
                        res.Append(replacement);
                    } else {
                        res.Append("<UNKNOWN:");
                        res.Append(name);
                        res.Append(">");
                    }
                    pos++;
                } else {
                    res.Append('$');
                }
                break;
            default:
                res.Append(input[pos++]);
                break;
        }
    }
    return res.ToString();
}
public static void Main() {
    const string input = "Here is a test string contain $(variableA) and $(variableB$(variableC))";
    var vars = new Dictionary<string, string> {
        {"variableA", "A"}, {"variableB", "B"}, {"variableC", "C"}, {"variableBC", "Y"}
    };
    int pos = 0;
    Console.WriteLine(Replace(input, ref pos, vars));
}

This solution reuses the implementation of Replace to built the name of the variable that you would like to replace by calling itself with the stopOnClose flag set to true. Top-level invocation does not stop on reaching the ')' symbol, letting you use it unescaped.

Here is a demo on ideone.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top