I've got a string that consists of an arbitrary combination of text and {}
delimited python code, for instance, A plus b is {a + b}
. However, braces are used for dictionary and set literals in python, so You chose the {{1:"first", 2:"second"}[choice]} option
should also be interpretted correctly. It's also valid to have more than one python expression in the input, so You picked {choice1} and {choice2}
is valid.
Here's my current code:
protected String ParseStringForVariable([NotNull] String str)
{
PythonEngine.PythonEngine pythonEngine = GetCurrentCore().PythonEngine;
for (int i = 0; i < str.Length; i++)
{
if (str[i] != '{')
{
continue;
}
int opening = i;
foreach (var expression in from closing in str.IndexesWhere('}'.Equals)
where closing > opening
select new
{
Template = str.Substring(opening, closing - opening + 1),
Code = str.Substring(opening + 1, closing - opening - 1)
})
{
PythonByteCode compiled;
try
{
compiled = pythonEngine.Compile(expression.Code, PythonByteCode.SourceCodeType.Expression);
}
catch (PythonParseException)
{
// not valid python, try next expression
continue;
}
String result = pythonEngine.Evaluate(compiled).ToString();
str = str.Replace(expression.Template, result);
break;
}
}
return str;
}
It works by looking at progressively longer strings, attempting to parse them, and ignoring them if it's not valid python. This is done with the PythonEngine
class, which is a wrapper around the IronPython interpretter, and has an extensive test suite, so can assumed to be correct.
It appears to burp slightly if the value of the first of multiple python expression contains an opening brace:
{"{"} {"}"}
, what's the best way to prevent that?Resharper is complaining about access to modified closures, can you provide a test case that exposes why that is an issue?
It works under all inputs I've tested it with, but what edge cases should be included in the test suite? (It's intended behaviour that invalid python code is left as-is). Current thoughts include:
- Empty string
- without braces
- empty braces
- valid python in braces
- invalid python
- both valid and invalid
- both valid and empty
- both invalid and empty
- valid, nested braces
- invalid, nested braces
- valid, evaluated to contain open brace
- valid, evaluated to contain close brace - irrelevant, as parsing is LTR?
- valid, evaluated to contain open brace followed by further invalid
- valid, evaluated to contain open brace followed by further empty
- unmatched open brace
- unmatched close brace
Are there any improvements that jump out? Clarity, performance, style?
PythonByteCode
anywhere. \$\endgroup\$