Jak wyjść z ciągu JSON?


101

Czy są dostępne jakieś klasy / funkcje, których można użyć do łatwego usuwania kodu JSON? Wolałbym nie pisać własnych.


4
JsonConvert.ToString () pracował dla mnie.
Martin Lottering

@MartinLottering Dziękuję !!! Szukałem sposobu, aby uzyskać JSON do sformatowanego ciągu. Żadna z poniższych odpowiedzi nie zadziałała, ale zadziałało.
GhostShaman

Odpowiedzi:



50

Dla osób korzystających z bardzo popularnego projektu Json.Net firmy Newtonsoft zadanie jest banalne:

using Newtonsoft.Json;

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

Ten kod drukuje:

„a \\ b”

Oznacza to, że wynikowa wartość ciągu zawiera cudzysłowy, a także odwrotny ukośnik uciekający.


2
Nie mogę odtworzyć tej metody deserializacji zakodowanej i uciekającej ścieżki UNC. Moja ścieżka "WatchedPath": "\\\\myserver\\output"staje "\"\\\\\\\\myserver\\\\output\""się czymś nie do przyjęcia.
sen

3
Powyższa metoda nie służy do deserializacji - rater jest używana, gdy chcesz ręcznie utworzyć tekst JSON i masz ciąg C # i musisz uzyskać jego odpowiednią reprezentację jako tekst.
Dror Harari

@slestak, myślę, że mam ten sam problem, co ty tutaj. Znalazłeś rozwiązanie?
GP24

@ GP24 IIRC, nie zrobiłem. Przepraszam, nie mam więcej informacji.
slestak

Nie ma problemu, dziękuję za odpowiedź. Zrobiłem to, jeśli ci to pomoże: yourAnnoyingDoubleEncodedString.Replace ("\\\\", "\\"). Zastąp ("\\\", "\" ");
GP24

40

Opierając się na odpowiedzi Dejana , możesz zaimportować System.Web.Helperszestaw .NET Framework , a następnie użyć następującej funkcji:

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

SubstringPołączenie jest konieczne, ponieważ Encodeautomatycznie otacza struny cudzysłów.


Wygląda na to, że System.Web.Helpers nie jest dostępny przed .Net 4.0
SerG

… I nie więcej także w Visual Studio 2015.
Lapo

5
Jest to część ASP.NET Web Pages 2.0. Można go dodać za pomocą NuGet. Nie jest częścią struktury.
Murven

31

Tak, po prostu dodaj następującą funkcję do swojej klasy Utils lub coś takiego:

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

3
Dlaczego musisz uciec /?
drzaus

Wiem, że to stara odpowiedź i cieszę się, że została podana, ponieważ nie chciałem polegać na żadnych bibliotekach zewnętrznych, ale zauważyłem, że domyślna wielkość znaku kontrolnego zawsze zwraca „\\ u000X”. Uważam, że najpierw musisz rzucić char na int. Rozważ zastąpienie gostring t = "000" + ((int)c).ToString("X");
Jan Discart

Prawidłowy domyślny przypadek to:t = "000" + String.Format("{0:X}",(int) c);
daniatic

To, czego tak naprawdę chcemy, to ” "\\u" + ((int)c).ToString("X4") (chociaż myślę, że dwa Appends byłyby jeszcze lepsze)
James Curran

16

Użyłem następującego kodu, aby zmienić wartość ciągu dla json. Musisz dodać swój „” ”do wyniku następującego kodu:

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

1
To naprawdę uratowało mi dzień. Wielkie dzięki!
casaout

8
Nie używaj tego kodu w produkcji! Ta funkcja ucieczki JSON powoduje pominięcie ważnych znaków specjalnych. Zobacz: stackoverflow.com/a/33799784
vog

2
Ten kod nie obejmuje wszystkich przypadków specjalnych. NIE używać w produkcji.
Envil

2
wymyśl na nowo koło i
wprowadź

6

Oferowane tutaj metody są wadliwe.
Po co zapuszczać się tak daleko, skoro można po prostu użyć System.Web.HttpUtility.JavaScriptEncode?

Jeśli korzystasz z niższej platformy, możesz po prostu skopiować i wkleić ją z mono

Dzięki uprzejmości mono-project @ 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();
    }

Można to zagęścić w

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


4

Przeprowadziłem testy szybkości dla niektórych z tych odpowiedzi dla długiego i krótkiego ciągu. Kod Clive'a Patersona wygrał sporo, prawdopodobnie dlatego, że inni biorą pod uwagę opcje serializacji. Oto moje wyniki:

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

A oto kod testowy:

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



2
String.Format("X", c);

To po prostu wyprowadza: X

Spróbuj tego zamiast tego:

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

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

2

I ładna jedna linijka, użyłem JsonConvert jak inni, ale dodałem podciąg, aby usunąć dodane cudzysłowy i ukośnik odwrotny.

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


0

Zdecydowałem się użyć System.Web.Script.Serialization.JavaScriptSerializer.

Mam małą statyczną klasę pomocniczą zdefiniowaną w następujący sposób:

internal static partial class Serialization
{
    static JavaScriptSerializer serializer;
    
    static Serialization()
    {
        serializer = new JavaScriptSerializer();
        serializer.MaxJsonLength = Int32.MaxValue;
    }
    public static string ToJSON<T>(T obj)
    {
        return serializer.Serialize(obj);
    }
    public static T FromJSON<T>(string data)
    {
        if (Common.IsEmpty(data))
            return default(T);
        else
            return serializer.Deserialize<T>(data);
    }
}

Aby serializować wszystko, do czego właśnie dzwonię Serialization.ToJSON(itemToSerialize)

Po prostu dzwonię do deserializacji Serialization.FromJSON<T>(jsonValueOfTypeT)

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.