2010-07-21 8 views
7

Si tengo una cadena que contiene una expresión literal C# string puedo "ampliar" en tiempo de ejecución¿Puedo ampliar una cadena que contiene expresiones literales C# en tiempo de ejecución

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

Como Can I convert a C# string value to an escaped string literal, pero a la inversa?

+0

Sabes que tu Assert fallará, ¿no es así? Y el segundo método no usa su parámetro. –

+1

Es un Nunit Assert, he editado el código para usar un debug.assert. El segundo método es un apéndice TDD (diseño impulsado por prueba); la respuesta a la pregunta proporcionará una solución más general, –

+0

, pero aún presenta 2 funciones no relacionadas. Esa última línea me ayudó a entender, el código solo me confundió. –

Respuesta

11

similares a Mikael respuesta, pero utilizando el 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; 
    } 

Usted puede ser mejor usar un diccionario de comodines y sólo la sustitución en la cadena.

+0

Buena llamada sobre el uso del proveedor de csharp. Estaba tan acostumbrado a usar eval y modifiqué un código que ya tenía que echaba de menos esta forma obvia de hacerlo. –

+0

Gracias, eso es justo lo que estaba buscando –

+0

+1 - Muy buena respuesta. –

3

No estoy seguro de si esta es la manera más simple, pero al hacer referencia al espacio de nombres Microsoft.JScript puede volver a analizarlo con la función javascript eval.

Aquí está una prueba para el código en la parte inferior

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

Esto a su vez, el \ r en un retorno de carro.

Y la aplicación

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

Si usted está buscando para hacer "simple" caracteres de escape como se define en la Microsoft site, puede utilizar esta rutina y salvar a la importación de librerías externas:

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

Aquí hay una unidad de prueba para demostrarlo:

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

dude en modificar el EscapeMap o cambiar el nombre de la función UnescapeSimple (raro lo sé).

Tenga en cuenta que esta solución no maneja los caracteres de escape Unicode o hexadecimal u octal, simplemente maneja los caracteres simples de un solo carácter.

1

Regex.Unescape sería mi método de elección.

+0

gracias, esto es exactamente lo que estaba buscando, por mi propio problema – Rayanth

Cuestiones relacionadas