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.

theringostarrs
źródło
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:

82

używam System.Web.HttpUtility.JavaScriptStringEncode

string quoted = HttpUtility.JavaScriptStringEncode(input);
xmedeko
źródło
5
Użyłem tego, aby uniknąć brakujących danych System.Web.Helpers.Json.Encodew VS2015, ale potrzebuje on również (input, true)parametru, aby uwzględnić również rzeczywiste cytaty.
Lapo
To było dla mnie brakujące ogniwo
Jawid Hassim
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.

Dror Harari
źródło
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.

Rok Strniša
źródło
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();
    }
Clive Paterson
źródło
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();
}
Amit Bhagat
źródło
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();
    }
}
Stefan Steiger
źródło
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();
}
innominate227
źródło
3

W .Net Core 3+ i .Net 5+:

string escapedJsonString = JsonEncodedText.Encode(jsonString);
Jawad Al Shaikh
źródło
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'));
user2058470
źródło
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);
Joshua Duxbury
źródło
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)

AnthonyVO
źródło