2010-07-21 12 views
7

Se ho una stringa che contiene un'espressione letterale C# stringa posso "espandere" è in fase di esecuzionePosso espandere una stringa che contiene C# espressioni letterali in fase di esecuzione

public void TestEvaluateString() 
    { 
     string Dummy = EvalString(@"Contains \r\n new line"); 
     Debug.Assert(Dummy == "Contains \r\n new line"); 
    } 

    private string EvalString(string input) 
    { 
     return "Contains \r\n new line"; 
    } 

Come Can I convert a C# string value to an escaped string literal, ma in senso inverso?

+0

Tu conosci il tuo Assert fallirà, non è vero? E il secondo metodo non usa il suo parametro. –

+1

È un Nunit Assert, ho modificato il codice per usare un debug.assert. Il secondo metodo è uno stub TDD (Test driven design), la risposta alla domanda fornirà una soluzione più generale –

+0

ancora presenti 2 funzioni non correlate. L'ultima riga mi ha aiutato a capire, il codice mi ha solo confuso. –

risposta

11

Simile a Mikael risposta, ma utilizzando il 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; 
    } 

si potrebbe essere meglio utilizzare un dizionario di caratteri jolly e proprio la loro sostituzione nella stringa.

+0

Una buona chiamata sull'utilizzo del provider csharp. Ero così sintonizzato sull'uso di eval e ho modificato il codice che avevo già avuto, mi mancava questo modo ovvio di farlo. –

+0

Grazie, è proprio quello che stavo cercando –

+0

+1 - Ottima risposta davvero. –

3

Non sono sicuro se questo è il modo più semplice, ma facendo riferimento allo spazio dei nomi Microsoft.JScript è possibile eseguire nuovamente l'analisi con la funzione javascript eval.

Ecco un test per il codice in basso

var evalToString = Evaluator.MyStr("test \\r\\n test"); 

Questo trasformerà il \ r in un ritorno a capo.

E l'attuazione

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; 
       } 
      } 
     }"; 
} 
2

Se stai solo cercando di fare "semplice" fuga personaggi come definito sulla Microsoft site, è possibile utilizzare questa routine e salvare importazione librerie esterne:

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(); 
    } 
} 

Ecco uno unit test per dimostrarlo:

[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)); 
    } 

Sentitevi liberi di modificare l'EscapeMap o rinominare la funzione UnescapeSimple (imbarazzante lo so).

Si noti che questa soluzione non gestisce caratteri di escape Unicode o esadecimale o ottale, semplicemente gestisce i semplici quelli singolo carattere.

1

Regex.Unescape sarebbe il mio metodo di scelta.

+0

grazie, questo è esattamente quello che stavo cercando, per il mio problema – Rayanth

Problemi correlati