If I have a string that contains a c# string literal expression can I \"expand\" it at runtime
public void TestEvaluateString()
{
string Dumm
If you're just looking to do "simple" escape characters as defined on the Microsoft site, you can use this routine and save importing external libs:
public static class StringExtensions
{
/* https://msdn.microsoft.com/en-us/library/aa691087(v=vs.71).aspx */
private readonly static SortedDictionary<char, char> EscapeMap = new SortedDictionary<char, char>
{
{ '\'', '\'' },
{ '"', '\"' },
{ '\\', '\\' },
{ '0', '\0' },
{ 'a', '\a' },
{ 'b', '\b' },
{ 'f', '\f' },
{ 'n', '\n' },
{ 'r', '\r' },
{ 't', '\t' },
{ 'v', '\v' },
};
public static string UnescapeSimple(this string escaped)
{
if (escaped == null)
return escaped;
var sb = new StringBuilder();
bool inEscape = false;
var s = 0;
for (var i = 0; i < escaped.Length; i++)
{
if (!inEscape && escaped[i] == '\\')
{
inEscape = true;
continue;
}
if (inEscape)
{
char mapChar;
if (EscapeMap.TryGetValue(escaped[i], out mapChar))
{
sb.Append(escaped.Substring(s, i - s - 1));
sb.Append(mapChar);
s = i + 1;
}
inEscape = false;
}
}
sb.Append(escaped.Substring(s));
return sb.ToString();
}
}
Here's a unit test to prove it:
[TestMethod]
public void UnescapeSimpleTest()
{
var noEscapes = @"This is a test".UnescapeSimple();
Assert.AreEqual("This is a test", noEscapes, nameof(noEscapes));
var singleEscape = @"\n".UnescapeSimple();
Assert.AreEqual("\n", singleEscape, nameof(singleEscape));
var allEscape = @"\'\""\\\0\a\b\f\n\r\t\v".UnescapeSimple();
Assert.AreEqual("\'\"\\\0\a\b\f\n\r\t\v", allEscape, nameof(allEscape));
var textInEscapes = @"\tthis\n\ris\\a\ntest".UnescapeSimple();
Assert.AreEqual("\tthis\n\ris\\a\ntest", textInEscapes, nameof(textInEscapes));
var backslashNoEscapes = @"\,\h\qtest".UnescapeSimple();
Assert.AreEqual(@"\,\h\qtest", backslashNoEscapes, nameof(backslashNoEscapes));
var emptyStr = "".UnescapeSimple();
Assert.AreEqual("", emptyStr, nameof(emptyStr));
// Prove Enviroment.NewLine is "\r\n" and not "\n\r" (Windows PC)
var newLine = @"\r\n".UnescapeSimple();
Assert.AreEqual(Environment.NewLine, newLine, nameof(newLine));
// Double check prior test (Windows PC)
var newLineWrong = @"\n\r".UnescapeSimple();
Assert.AreNotEqual(Environment.NewLine, newLineWrong, nameof(newLineWrong));
}
Feel free to tweak the EscapeMap or rename the function UnescapeSimple (awkward I know).
Note that this solution doesn't handle Unicode escape characters or hex or octal, it just handles the simple single character ones.
Not sure if this is the simplest way, but by referencing the Microsoft.JScript
namespace you can reparse it with the javascript eval
function.
Here's a test for the code at the bottom
var evalToString = Evaluator.MyStr("test \\r\\n test");
This will turn the \r into a carriage return.
And the implementation
public class Evaluator
{
public static object MyStr(string statement)
{
return _evaluatorType.InvokeMember(
"MyStr",
BindingFlags.InvokeMethod,
null,
_evaluator,
new object[] { statement }
);
}
static Evaluator()
{
ICodeCompiler compiler;
compiler = new JScriptCodeProvider().CreateCompiler();
CompilerParameters parameters;
parameters = new CompilerParameters();
parameters.GenerateInMemory = true;
CompilerResults results;
results = compiler.CompileAssemblyFromSource(parameters, _jscriptSource);
Assembly assembly = results.CompiledAssembly;
_evaluatorType = assembly.GetType("Evaluator.Evaluator");
_evaluator = Activator.CreateInstance(_evaluatorType);
}
private static object _evaluator = null;
private static Type _evaluatorType = null;
private static readonly string _jscriptSource =
@"package Evaluator
{
class Evaluator
{
public function MyStr(expr : String) : String
{
var x;
eval(""x='""+expr+""';"");
return x;
}
}
}";
}
Regex.Unescape would be my method of choice.
Similar to Mikael answer but using the CSharpCodeProvider:
public static string ParseString(string txt)
{
var provider = new Microsoft.CSharp.CSharpCodeProvider();
var prms = new System.CodeDom.Compiler.CompilerParameters();
prms.GenerateExecutable = false;
prms.GenerateInMemory = true;
var results = provider.CompileAssemblyFromSource(prms, @"
namespace tmp
{
public class tmpClass
{
public static string GetValue()
{
return " + "\"" + txt + "\"" + @";
}
}
}");
System.Reflection.Assembly ass = results.CompiledAssembly;
var method = ass.GetType("tmp.tmpClass").GetMethod("GetValue");
return method.Invoke(null, null) as string;
}
You might be better off using a dictionary of wildcards and just replacing them in the string.