Can I expand a string that contains C# literal expressions at runtime

后端 未结 4 758
后悔当初
后悔当初 2020-11-29 11:36

If I have a string that contains a c# string literal expression can I \"expand\" it at runtime

    public void TestEvaluateString()
    {
        string Dumm         


        
相关标签:
4条回答
  • 2020-11-29 11:53

    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.

    0 讨论(0)
  • 2020-11-29 12:01

    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;
                  }
               }
            }";
    }
    
    0 讨论(0)
  • 2020-11-29 12:13

    Regex.Unescape would be my method of choice.

    0 讨论(0)
  • 2020-11-29 12:18

    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.

    0 讨论(0)
提交回复
热议问题