Wie entkomme ich JSON-String?

96

Gibt es Klassen / Funktionen, die für ein einfaches JSON-Escape verwendet werden können? Ich möchte lieber nicht meine eigenen schreiben müssen.

Theringostarrs
quelle
3
JsonConvert.ToString () hat bei mir funktioniert.
Martin Lottering

Antworten:

74

ich benutze System.Web.HttpUtility.JavaScriptStringEncode

string quoted = HttpUtility.JavaScriptStringEncode(input);
xmedeko
quelle
5
Ich habe dies verwendet, um das Fehlen System.Web.Helpers.Json.Encodein VS2015 zu vermeiden , aber der (input, true)Parameter muss auch die tatsächlichen Anführungszeichen enthalten.
Lapo
47

Für diejenigen, die das sehr beliebte Json.Net-Projekt von Newtonsoft verwenden, ist die Aufgabe trivial:

using Newtonsoft.Json;

....
var s = JsonConvert.ToString(@"a\b");
Console.WriteLine(s);
....

Dieser Code druckt:

"a \\ b"

Das heißt, der resultierende Zeichenfolgenwert enthält die Anführungszeichen sowie den maskierten Backslash.

Dror Harari
quelle
2
Ich kann diese Methode zum Deserialisieren eines codierten und entkommenen unc-Pfads nicht reproduzieren. Mein Weg "WatchedPath": "\\\\myserver\\output"wird "\"\\\\\\\\myserver\\\\output\""ziemlich inakzeptabel.
Slestak
3
Die obige Methode ist nicht zum Deserialisieren gedacht. Sie wird verwendet, wenn Sie einen JSON-Text manuell erstellen möchten und eine C # -String haben und die richtige Darstellung als Text erhalten müssen.
Dror Harari
@ Slestak, ich glaube, ich stehe vor dem gleichen Problem, mit dem Sie hier waren. Haben Sie eine Lösung gefunden?
GP24
@ GP24 IIRC habe ich nicht. Entschuldigung, ich habe keine weiteren Informationen.
Slestak
Kein Problem, danke für die Antwort. Ich habe dies getan, wenn es Ihnen hilft: yourAnnoyingDoubleEncodedString.Replace ("\\\\", "\\"). Replace ("\\\" "," \ "");
GP24
38

Aufbauend auf der Antwort von Dejan können Sie die .NET Framework-Assembly importierenSystem.Web.Helpers und dann die folgende Funktion verwenden:

static string EscapeForJson(string s) {
  string quoted = System.Web.Helpers.Json.Encode(s);
  return quoted.Substring(1, quoted.Length - 2);
}

Der SubstringAufruf ist erforderlich, da EncodeZeichenfolgen automatisch in doppelte Anführungszeichen gesetzt werden.

Rok Strniša
quelle
Sieht aus wie System.Web.Helpers ist nicht verfügbar vor .Net 4.0
SerG
… Und nicht mehr in Visual Studio 2015.
Lapo
5
Dies ist Teil von ASP.NET Web Pages 2.0. Es kann mit NuGet hinzugefügt werden. Es ist nicht Teil des Rahmens.
Murven
30

Ja, fügen Sie Ihrer Utils-Klasse einfach die folgende Funktion hinzu oder so:

    public static string cleanForJSON(string s)
    {
        if (s == null || s.Length == 0) {
            return "";
        }

        char         c = '\0';
        int          i;
        int          len = s.Length;
        StringBuilder sb = new StringBuilder(len + 4);
        String       t;

        for (i = 0; i < len; i += 1) {
            c = s[i];
            switch (c) {
                case '\\':
                case '"':
                    sb.Append('\\');
                    sb.Append(c);
                    break;
                case '/':
                    sb.Append('\\');
                    sb.Append(c);
                    break;
                case '\b':
                    sb.Append("\\b");
                    break;
                case '\t':
                    sb.Append("\\t");
                    break;
                case '\n':
                    sb.Append("\\n");
                    break;
                case '\f':
                    sb.Append("\\f");
                    break;
                case '\r':
                    sb.Append("\\r");
                    break;
                default:
                    if (c < ' ') {
                        t = "000" + String.Format("X", c);
                        sb.Append("\\u" + t.Substring(t.Length - 4));
                    } else {
                        sb.Append(c);
                    }
                    break;
            }
        }
        return sb.ToString();
    }
Clive Paterson
quelle
3
Warum musst du fliehen /?
Drzaus
Ich weiß, dass dies eine alte Antwort ist, und ich bin froh zu sehen, dass dies gegeben wurde, da ich mich nicht auf externe Bibliotheken verlassen wollte, aber ich habe festgestellt, dass der Standardfall für ein Steuerzeichen immer "\\ u000X" zurückgibt. Ich glaube, Sie müssen den Char zuerst auf einen Int werfen. Erwägen Sie, es durchstring t = "000" + ((int)c).ToString("X");
Jan Discart
Der korrekte Standardfall muss sein:t = "000" + String.Format("{0:X}",(int) c);
daniatic
16

Ich habe folgenden Code verwendet, um den Zeichenfolgenwert für json zu umgehen. Sie müssen Ihr '"' zur Ausgabe des folgenden Codes hinzufügen:

public static string EscapeStringValue(string value)
{
    const char BACK_SLASH = '\\';
    const char SLASH = '/';
    const char DBL_QUOTE = '"';

    var output = new StringBuilder(value.Length);
    foreach (char c in value)
    {
        switch (c)
        {
            case SLASH:
                output.AppendFormat("{0}{1}", BACK_SLASH, SLASH);
                break;

            case BACK_SLASH:
                output.AppendFormat("{0}{0}", BACK_SLASH);
                break;

            case DBL_QUOTE:
                output.AppendFormat("{0}{1}",BACK_SLASH,DBL_QUOTE);
                break;

            default:
                output.Append(c);
                break;
        }
    }

    return output.ToString();
}
Amit Bhagat
quelle
1
Das hat mir wirklich den Tag gerettet. Vielen Dank!
Casaout
8
Verwenden Sie diesen Code nicht in der Produktion! Bei dieser JSON-Flucht fehlen wichtige Sonderzeichen. Siehe: stackoverflow.com/a/33799784
VOG
2
Dieser Code deckt nicht alle Sonderfälle ab. NICHT in der Produktion verwenden.
Envil
2
Das Rad neu zu erfinden und in besonderen Fällen einen Fehler einzuführen, ist keine gute Antwort
Xilmiki
6

Die hier angebotenen Methoden sind fehlerhaft.
Warum so weit gehen, wenn Sie nur System.Web.HttpUtility.JavaScriptEncode verwenden könnten?

Wenn Sie sich in einem niedrigeren Framework befinden, können Sie es einfach kopieren und aus Mono einfügen

Mit freundlicher Genehmigung des Monoprojekts @ https://github.com/mono/mono/blob/master/mcs/class/System.Web/System.Web/HttpUtility.cs

    public static string JavaScriptStringEncode(string value, bool addDoubleQuotes)
    {
        if (string.IsNullOrEmpty(value))
            return addDoubleQuotes ? "\"\"" : string.Empty;

        int len = value.Length;
        bool needEncode = false;
        char c;
        for (int i = 0; i < len; i++)
        {
            c = value[i];

            if (c >= 0 && c <= 31 || c == 34 || c == 39 || c == 60 || c == 62 || c == 92)
            {
                needEncode = true;
                break;
            }
        }

        if (!needEncode)
            return addDoubleQuotes ? "\"" + value + "\"" : value;

        var sb = new System.Text.StringBuilder();
        if (addDoubleQuotes)
            sb.Append('"');

        for (int i = 0; i < len; i++)
        {
            c = value[i];
            if (c >= 0 && c <= 7 || c == 11 || c >= 14 && c <= 31 || c == 39 || c == 60 || c == 62)
                sb.AppendFormat("\\u{0:x4}", (int)c);
            else switch ((int)c)
                {
                    case 8:
                        sb.Append("\\b");
                        break;

                    case 9:
                        sb.Append("\\t");
                        break;

                    case 10:
                        sb.Append("\\n");
                        break;

                    case 12:
                        sb.Append("\\f");
                        break;

                    case 13:
                        sb.Append("\\r");
                        break;

                    case 34:
                        sb.Append("\\\"");
                        break;

                    case 92:
                        sb.Append("\\\\");
                        break;

                    default:
                        sb.Append(c);
                        break;
                }
        }

        if (addDoubleQuotes)
            sb.Append('"');

        return sb.ToString();
    }

Dies kann verdichtet werden

// https://github.com/mono/mono/blob/master/mcs/class/System.Json/System.Json/JsonValue.cs
public class SimpleJSON
{

    private static  bool NeedEscape(string src, int i)
    {
        char c = src[i];
        return c < 32 || c == '"' || c == '\\'
            // Broken lead surrogate
            || (c >= '\uD800' && c <= '\uDBFF' &&
                (i == src.Length - 1 || src[i + 1] < '\uDC00' || src[i + 1] > '\uDFFF'))
            // Broken tail surrogate
            || (c >= '\uDC00' && c <= '\uDFFF' &&
                (i == 0 || src[i - 1] < '\uD800' || src[i - 1] > '\uDBFF'))
            // To produce valid JavaScript
            || c == '\u2028' || c == '\u2029'
            // Escape "</" for <script> tags
            || (c == '/' && i > 0 && src[i - 1] == '<');
    }



    public static string EscapeString(string src)
    {
        System.Text.StringBuilder sb = new System.Text.StringBuilder();

        int start = 0;
        for (int i = 0; i < src.Length; i++)
            if (NeedEscape(src, i))
            {
                sb.Append(src, start, i - start);
                switch (src[i])
                {
                    case '\b': sb.Append("\\b"); break;
                    case '\f': sb.Append("\\f"); break;
                    case '\n': sb.Append("\\n"); break;
                    case '\r': sb.Append("\\r"); break;
                    case '\t': sb.Append("\\t"); break;
                    case '\"': sb.Append("\\\""); break;
                    case '\\': sb.Append("\\\\"); break;
                    case '/': sb.Append("\\/"); break;
                    default:
                        sb.Append("\\u");
                        sb.Append(((int)src[i]).ToString("x04"));
                        break;
                }
                start = i + 1;
            }
        sb.Append(src, start, src.Length - start);
        return sb.ToString();
    }
}
Stefan Steiger
quelle
4

Bei einigen dieser Antworten habe ich Geschwindigkeitstests für eine lange und eine kurze Zeichenfolge durchgeführt. Clive Patersons Code hat ein gutes Stück gewonnen, vermutlich weil die anderen Serialisierungsoptionen berücksichtigen. Hier sind meine Ergebnisse:

Apple Banana
System.Web.HttpUtility.JavaScriptStringEncode: 140ms
System.Web.Helpers.Json.Encode: 326ms
Newtonsoft.Json.JsonConvert.ToString: 230ms
Clive Paterson: 108ms

\\some\long\path\with\lots\of\things\to\escape\some\long\path\t\with\lots\of\n\things\to\escape\some\long\path\with\lots\of\"things\to\escape\some\long\path\with\lots"\of\things\to\escape
System.Web.HttpUtility.JavaScriptStringEncode: 2849ms
System.Web.Helpers.Json.Encode: 3300ms
Newtonsoft.Json.JsonConvert.ToString: 2827ms
Clive Paterson: 1173ms

Und hier ist der Testcode:

public static void Main(string[] args)
{
    var testStr1 = "Apple Banana";
    var testStr2 = @"\\some\long\path\with\lots\of\things\to\escape\some\long\path\t\with\lots\of\n\things\to\escape\some\long\path\with\lots\of\""things\to\escape\some\long\path\with\lots""\of\things\to\escape";

    foreach (var testStr in new[] { testStr1, testStr2 })
    {
        var results = new Dictionary<string,List<long>>();

        for (var n = 0; n < 10; n++)
        {
            var count = 1000 * 1000;

            var sw = Stopwatch.StartNew();
            for (var i = 0; i < count; i++)
            {
                var s = System.Web.HttpUtility.JavaScriptStringEncode(testStr);
            }
            var t = sw.ElapsedMilliseconds;
            results.GetOrCreate("System.Web.HttpUtility.JavaScriptStringEncode").Add(t);

            sw = Stopwatch.StartNew();
            for (var i = 0; i < count; i++)
            {
                var s = System.Web.Helpers.Json.Encode(testStr);
            }
            t = sw.ElapsedMilliseconds;
            results.GetOrCreate("System.Web.Helpers.Json.Encode").Add(t);

            sw = Stopwatch.StartNew();
            for (var i = 0; i < count; i++)
            {
                var s = Newtonsoft.Json.JsonConvert.ToString(testStr);
            }
            t = sw.ElapsedMilliseconds;
            results.GetOrCreate("Newtonsoft.Json.JsonConvert.ToString").Add(t);

            sw = Stopwatch.StartNew();
            for (var i = 0; i < count; i++)
            {
                var s = cleanForJSON(testStr);
            }
            t = sw.ElapsedMilliseconds;
            results.GetOrCreate("Clive Paterson").Add(t);
        }

        Console.WriteLine(testStr);
        foreach (var result in results)
        {
            Console.WriteLine(result.Key + ": " + Math.Round(result.Value.Skip(1).Average()) + "ms");
        }
        Console.WriteLine();
    }

    Console.ReadLine();
}
innominate227
quelle
2
String.Format("X", c);

Das gibt nur aus: X.

Versuchen Sie stattdessen Folgendes:

string t = ((int)c).ToString("X");

sb.Append("\\u" + t.PadLeft(4, '0'));
user2058470
quelle
2

Ich habe einen schönen Einzeiler verwendet, JsonConvert wie andere verwendet, aber Teilzeichenfolgen hinzugefügt, um die hinzugefügten Anführungszeichen und den umgekehrten Schrägstrich zu entfernen.

 var escapedJsonString = JsonConvert.ToString(JsonString).Substring(1, JsonString.Length - 2);
Joshua Duxbury
quelle
1

In .Net Core 3+ und .Net 5+:

string escapedJsonString = JsonEncodedText.Encode(jsonString);
Jawad Al Shaikh
quelle