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?
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.