Làm cách nào để thoát chuỗi JSON?


97

Có bất kỳ lớp / chức năng nào có sẵn để sử dụng để dễ dàng thoát JSON không? Tôi không muốn phải viết của riêng tôi.


3
JsonConvert.ToString () đã làm việc cho tôi.
Martin Lottering,

Câu trả lời:


74

tôi sử dụng System.Web.HttpUtility.JavaScriptStringEncode

string quoted = HttpUtility.JavaScriptStringEncode(input);

5
Tôi đã sử dụng điều này để tránh bị thiếu System.Web.Helpers.Json.Encodetrong VS2015, nhưng nó cũng cần (input, true)tham số để bao gồm các trích dẫn thực tế.
lapo

47

Đối với những người sử dụng dự án Json.Net rất phổ biến từ Newtonsoft, nhiệm vụ là rất nhỏ:

using Newtonsoft.Json;

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

Mã này in:

"a \\ b"

Nghĩa là, giá trị chuỗi kết quả chứa các dấu ngoặc kép cũng như dấu gạch chéo ngược thoát.


2
Tôi không thể tạo lại phương pháp này để giải mã hóa một đường dẫn chưa được mã hóa và thoát. Con đường của tôi "WatchedPath": "\\\\myserver\\output"trở thành "\"\\\\\\\\myserver\\\\output\""điều không thể chấp nhận được.
slestak

3
Phương pháp trên không phải để giải mã hóa - nó được sử dụng khi bạn muốn tạo văn bản JSON theo cách thủ công và bạn có một chuỗi C # và cần có được biểu diễn phù hợp của nó dưới dạng văn bản.
Dror Harari

@slestak, tôi nghĩ rằng tôi đang gặp phải vấn đề tương tự như bạn ở đây. Bạn đã tìm thấy một giải pháp?
GP24,

@ GP24 IIRC, tôi thì không. Xin lỗi tôi không có thêm thông tin.
slestak

Không sao, cảm ơn vì đã trả lời. Tôi đã làm điều này nếu nó giúp bạn: yourAnnoyingDoubleEncodedString.Replace ("\\\\", "\\"). Replace ("\\\" "," \ "");
GP24

38

Dựa trên câu trả lời của Dejan , những gì bạn có thể làm là nhập System.Web.Helpers.NET Framework lắp ráp , sau đó sử dụng chức năng sau:

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

Cuộc Substringgọi là bắt buộc, vì Encodetự động bao quanh chuỗi bằng dấu ngoặc kép.


Trông giống như System.Web.Helpers không có sẵn trước Net 4.0
SERG

… Và không còn nữa trong Visual Studio 2015.
lapo

5
Đây là một phần của ASP.NET Web Pages 2.0. Nó có thể được thêm vào bằng NuGet. Nó không phải là một phần của khuôn khổ.
Bị giết

30

Đúng, chỉ cần thêm hàm sau vào lớp Utils của bạn hoặc thứ gì đó:

    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
Tại sao bạn cần phải trốn thoát /?
drzaus

Tôi biết đây là một câu trả lời cũ và tôi rất vui khi thấy điều này đã được đưa ra vì tôi không muốn dựa vào bất kỳ thư viện bên ngoài nào, nhưng tôi nhận thấy rằng trường hợp mặc định cho một ký tự điều khiển sẽ luôn trả về "\\ u000X". Tôi tin rằng bạn cần chuyển char trước tiên sang một int. Xem xét thay thế nó bằngstring t = "000" + ((int)c).ToString("X");
Jan Discart

Trường hợp mặc định chính xác phải là:t = "000" + String.Format("{0:X}",(int) c);
daniatic

16

Tôi đã sử dụng mã sau để thoát giá trị chuỗi cho json. Bạn cần thêm '"' của mình vào đầu ra của mã sau:

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
Điều này thực sự đã cứu một ngày của tôi. Cảm ơn rất nhiều!
casaout,

8
Không sử dụng mã này trong sản xuất! Việc thoát JSON này bỏ sót các ký tự đặc biệt quan trọng. Xem: stackoverflow.com/a/33799784
vog

2
Mã này không bao gồm tất cả các trường hợp đặc biệt. KHÔNG sử dụng trong sản xuất.
Envil

2
minh lại bánh xe, và giới thiệu một số lỗi trong trường hợp đặc biệt, không phải là một câu trả lời tốt
Xilmiki

6

Các phương pháp được cung cấp ở đây bị lỗi.
Tại sao phải mạo hiểm xa như vậy khi bạn chỉ có thể sử dụng System.Web.HttpUtility.JavaScriptEncode?

Nếu bạn đang ở trong một khuôn khổ thấp hơn, bạn chỉ có thể sao chép và dán nó từ mono

Được phép của đơn dự án @ 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();
    }

Điều này có thể được nén thành

// 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

Tôi đã chạy các bài kiểm tra tốc độ trên một số câu trả lời này cho một chuỗi dài và một chuỗi ngắn. của Clive Paterson đã thắng được một chút, có lẽ là do những người khác đang tính đến các tùy chọn tuần tự hóa. Đây là kết quả của tôi:

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

Và đây là mã kiểm tra:

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

Điều đó chỉ xuất ra: X

Hãy thử cái này thay thế:

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

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

2

Tôi đẹp một chữ lót, đã sử dụng JsonConvert như những người khác nhưng đã thêm chuỗi con để loại bỏ các dấu ngoặc kép và dấu gạch chéo ngược đã thêm.

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

2

Trong .Net Core 3+ và .Net 5+:

string escapedJsonString = JsonEncodedText.Encode(jsonString);


0

Tôi đã chọn để sử dụng System.Web.Script.Serialization.JavaScriptSerializer.

Tôi có một lớp trợ giúp tĩnh nhỏ được định nghĩa như sau:

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

Để tuần tự hóa bất cứ thứ gì tôi chỉ cần gọi Serialization.ToJSON(itemToSerialize)

Để deserialize, tôi chỉ cần gọi Serialization.FromJSON<T>(jsonValueOfTypeT)

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.