web-dev-qa-db-fra.com

Puis-je convertir une valeur de chaîne C # en un littéral de chaîne échappé

En C #, puis-je convertir une valeur de chaîne en littéral, comme je le verrais dans le code? Je voudrais remplacer les onglets, les nouvelles lignes, etc. par leurs séquences d'échappement.

Si ce code:

Console.WriteLine(someString);

produit:

Hello
World!

Je veux ce code:

Console.WriteLine(ToLiteral(someString));

produire:

\tHello\r\n\tWorld!\r\n
170
Hallgrim

J'ai trouvé ça:

private static string ToLiteral(string input)
{
    using (var writer = new StringWriter())
    {
        using (var provider = CodeDomProvider.CreateProvider("CSharp"))
        {
            provider.GenerateCodeFromExpression(new CodePrimitiveExpression(input), writer, null);
            return writer.ToString();
        }
    }
}

Ce code:

var input = "\tHello\r\n\tWorld!";
Console.WriteLine(input);
Console.WriteLine(ToLiteral(input));

Produit:

    Hello
    World!
"\tHello\r\n\tWorld!"
158
Hallgrim

Qu'en est-il Regex.Escape (String) ?

Regex.Escape échappe à un ensemble minimal de caractères (\, *, +,?, |, {, [ (,), ^, $,., # Et espace) en les remplaçant par leur échappement codes.

26
Shqdooow

EDIT: Une approche plus structurée, incluant toutes les séquences d'échappement pour strings et chars. 
Ne remplace pas les caractères unicode par leur équivalent littéral . Ne cuisine pas non plus les œufs.

public class ReplaceString
{
    static readonly IDictionary<string, string> m_replaceDict 
        = new Dictionary<string, string>();

    const string ms_regexEscapes = @"[\a\b\f\n\r\t\v\\""]";

    public static string StringLiteral(string i_string)
    {
        return Regex.Replace(i_string, ms_regexEscapes, match);
    }

    public static string CharLiteral(char c)
    {
        return c == '\'' ? @"'\''" : string.Format("'{0}'", c);
    }

    private static string match(Match m)
    {
        string match = m.ToString();
        if (m_replaceDict.ContainsKey(match))
        {
            return m_replaceDict[match];
        }

        throw new NotSupportedException();
    }

    static ReplaceString()
    {
        m_replaceDict.Add("\a", @"\a");
        m_replaceDict.Add("\b", @"\b");
        m_replaceDict.Add("\f", @"\f");
        m_replaceDict.Add("\n", @"\n");
        m_replaceDict.Add("\r", @"\r");
        m_replaceDict.Add("\t", @"\t");
        m_replaceDict.Add("\v", @"\v");

        m_replaceDict.Add("\\", @"\\");
        m_replaceDict.Add("\0", @"\0");

        //The SO parser gets fooled by the verbatim version 
        //of the string to replace - @"\"""
        //so use the 'regular' version
        m_replaceDict.Add("\"", "\\\""); 
    }

    static void Main(string[] args){

        string s = "here's a \"\n\tstring\" to test";
        Console.WriteLine(ReplaceString.StringLiteral(s));
        Console.WriteLine(ReplaceString.CharLiteral('c'));
        Console.WriteLine(ReplaceString.CharLiteral('\''));

    }
}
23
Cristi Diaconescu
public static class StringHelpers
{
    private static Dictionary<string, string> escapeMapping = new Dictionary<string, string>()
    {
        {"\"", @"\\\"""},
        {"\\\\", @"\\"},
        {"\a", @"\a"},
        {"\b", @"\b"},
        {"\f", @"\f"},
        {"\n", @"\n"},
        {"\r", @"\r"},
        {"\t", @"\t"},
        {"\v", @"\v"},
        {"\0", @"\0"},
    };

    private static Regex escapeRegex = new Regex(string.Join("|", escapeMapping.Keys.ToArray()));

    public static string Escape(this string s)
    {
        return escapeRegex.Replace(s, EscapeMatchEval);
    }

    private static string EscapeMatchEval(Match m)
    {
        if (escapeMapping.ContainsKey(m.Value))
        {
            return escapeMapping[m.Value];
        }
        return escapeMapping[Regex.Escape(m.Value)];
    }
}
17
ICR

essayer:

var t = HttpUtility.JavaScriptStringEncode(s);
14
Arsen Zahray

La réponse de Hallgrim est excellente, mais les ajouts de "+", de nouvelle ligne et d'indentation ont été une rupture pour moi. Un moyen facile de le contourner est:

private static string ToLiteral(string input)
{
    using (var writer = new StringWriter())
    {
        using (var provider = CodeDomProvider.CreateProvider("CSharp"))
        {
            provider.GenerateCodeFromExpression(new CodePrimitiveExpression(input), writer, new CodeGeneratorOptions {IndentString = "\t"});
            var literal = writer.ToString();
            literal = literal.Replace(string.Format("\" +{0}\t\"", Environment.NewLine), "");
            return literal;
        }
    }
}
12
lesur

Implémentation pleinement fonctionnelle, incluant l'échappement de caractères non imprimables Unicode et ASCII. N'insère pas les signes "+" comme Réponse de Hallgrim .

    static string ToLiteral(string input) {
        StringBuilder literal = new StringBuilder(input.Length + 2);
        literal.Append("\"");
        foreach (var c in input) {
            switch (c) {
                case '\'': literal.Append(@"\'"); break;
                case '\"': literal.Append("\\\""); break;
                case '\\': literal.Append(@"\\"); break;
                case '\0': literal.Append(@"\0"); break;
                case '\a': literal.Append(@"\a"); break;
                case '\b': literal.Append(@"\b"); break;
                case '\f': literal.Append(@"\f"); break;
                case '\n': literal.Append(@"\n"); break;
                case '\r': literal.Append(@"\r"); break;
                case '\t': literal.Append(@"\t"); break;
                case '\v': literal.Append(@"\v"); break;
                default:
                    // ASCII printable character
                    if (c >= 0x20 && c <= 0x7e) {
                        literal.Append(c);
                    // As UTF16 escaped character
                    } else {
                        literal.Append(@"\u");
                        literal.Append(((int)c).ToString("x4"));
                    }
                    break;
            }
        }
        literal.Append("\"");
        return literal.ToString();
    }
11
Smilediver

Question interessante.

Si vous ne pouvez pas trouver une meilleure méthode, vous pouvez toujours remplacer.
Si vous optez pour cette option, vous pouvez utiliser cette liste de séquences d'échappement C #:

  • \ '- guillemet simple, nécessaire pour les littéraux de caractères
  • \ "- guillemet double, nécessaire pour les littéraux de chaîne
  • \ - barre oblique inverse
  • \ 0 - Caractère Unicode 0
  • \ a - Alerte (caractère 7)
  • \ b - Retour arrière (caractère 8)
  • \ f - Alimentation de formulaire (caractère 12)
  • \ n - Nouvelle ligne (caractère 10)
  • \ r - Retour de chariot (caractère 13)
  • \ t - Onglet horizontal (caractère 9)
  • \ v - citation verticale (caractère 11)
  • \ uxxxx - Séquence d'échappement Unicode pour les caractères de valeur hexadécimale xxxx
  • \ xn [n] [n] [n] - Séquence d'échappement Unicode pour les caractères de valeur hexadécimale nnnn (version de longueur variable de\uxxxx)
  • \ Uxxxxxxxx - Séquence d'échappement Unicode pour un caractère de valeur hexadécimale xxxxxxxx (pour générer des substituts) 

Cette liste se trouve dans la foire aux questions de C # Quelles sont les séquences d'échappement de caractères disponibles?

8
Nelson Reis

Voici une petite amélioration pour la réponse de Smilediver, cela n'échappera pas à tous les caractères sans ASCII mais seulement ceux-ci sont vraiment nécessaires.

using System;
using System.Globalization;
using System.Text;

public static class CodeHelper
{
    public static string ToLiteral(this string input)
    {
        var literal = new StringBuilder(input.Length + 2);
        literal.Append("\"");
        foreach (var c in input)
        {
            switch (c)
            {
                case '\'': literal.Append(@"\'"); break;
                case '\"': literal.Append("\\\""); break;
                case '\\': literal.Append(@"\\"); break;
                case '\0': literal.Append(@"\0"); break;
                case '\a': literal.Append(@"\a"); break;
                case '\b': literal.Append(@"\b"); break;
                case '\f': literal.Append(@"\f"); break;
                case '\n': literal.Append(@"\n"); break;
                case '\r': literal.Append(@"\r"); break;
                case '\t': literal.Append(@"\t"); break;
                case '\v': literal.Append(@"\v"); break;
                default:
                    if (Char.GetUnicodeCategory(c) != UnicodeCategory.Control)
                    {
                        literal.Append(c);
                    }
                    else
                    {
                        literal.Append(@"\u");
                        literal.Append(((ushort)c).ToString("x4"));
                    }
                    break;
            }
        }
        literal.Append("\"");
        return literal.ToString();
    }
}
4
deerchao
public static class StringEscape
{
  static char[] toEscape = "\0\x1\x2\x3\x4\x5\x6\a\b\t\n\v\f\r\xe\xf\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\"\\".ToCharArray();
  static string[] literals = @"\0,\x0001,\x0002,\x0003,\x0004,\x0005,\x0006,\a,\b,\t,\n,\v,\f,\r,\x000e,\x000f,\x0010,\x0011,\x0012,\x0013,\x0014,\x0015,\x0016,\x0017,\x0018,\x0019,\x001a,\x001b,\x001c,\x001d,\x001e,\x001f".Split(new char[] { ',' });

  public static string Escape(this string input)
  {
    int i = input.IndexOfAny(toEscape);
    if (i < 0) return input;

    var sb = new System.Text.StringBuilder(input.Length + 5);
    int j = 0;
    do
    {
      sb.Append(input, j, i - j);
      var c = input[i];
      if (c < 0x20) sb.Append(literals[c]); else sb.Append(@"\").Append(c);
    } while ((i = input.IndexOfAny(toEscape, j = ++i)) > 0);

    return sb.Append(input, j, input.Length - j).ToString();
  }
}
1
Serge N

Ma tentative d'ajouter ToVerbatim à la réponse acceptée ci-dessus de Hallgrim est la suivante:

private static string ToLiteral(string input)
{
    using (var writer = new StringWriter())
    {
        using (var provider = CodeDomProvider.CreateProvider("CSharp"))
        {
            provider.GenerateCodeFromExpression(new CodePrimitiveExpression(input), writer, new CodeGeneratorOptions { IndentString = "\t" });
            var literal = writer.ToString();
            literal = literal.Replace(string.Format("\" +{0}\t\"", Environment.NewLine), "");           
            return literal;
        }
    }
}

private static string ToVerbatim( string input )
{
    string literal = ToLiteral( input );
    string verbatim = "@" + literal.Replace( @"\r\n", Environment.NewLine );
    return verbatim;
}
1
Derek

La réponse de Hallgrim était excellente. Voici un petit tweak au cas où vous auriez besoin d'analyser des caractères d'espacement et des sauts de ligne supplémentaires avec une expression régulière c #. J'avais besoin de cela dans le cas d'une valeur Json sérialisée pour l'insertion dans des feuilles de Google. Je rencontrais des problèmes car le code insérait des tabulations, des +, des espaces, etc. 

  provider.GenerateCodeFromExpression(new CodePrimitiveExpression(input), writer, null);
  var literal = writer.ToString();
  var r2 = new Regex(@"\"" \+.\n[\s]+\""", RegexOptions.ECMAScript);
  literal = r2.Replace(literal, "");
  return literal;
0
Alexander Yoshi

Si les conventions JSON sont suffisantes pour les chaînes non échappées que vous voulez échapper et que vous utilisez déjà Newtonsoft.Json dans votre projet (il a une surcharge assez importante), vous pouvez utiliser ce package comme suit:

using System;
using Newtonsoft.Json;

public class Program
{
    public static void Main()
    {
    Console.WriteLine(ToLiteral( @"abc\n123") );
    }

    private static string ToLiteral(string input){
        return JsonConvert.DeserializeObject<string>("\"" + input + "\"");
    }
}
0
ehsan88