จะหลีกเลี่ยงสตริง JSON ได้อย่างไร


103

มีคลาส / ฟังก์ชันใดบ้างที่สามารถใช้สำหรับการหลีกเลี่ยง JSON ได้อย่างง่ายดาย ฉันไม่ต้องเขียนของตัวเอง


4
JsonConvert ToString () ทำงานให้ฉัน
Martin Lottering

@MartinLottering ขอบคุณ !!! ฉันกำลังมองหาวิธีรับ json เป็นสตริงที่จัดรูปแบบ คำตอบด้านล่างไม่ได้ผล แต่สิ่งนี้ทำได้
GhostShaman

คำตอบ:


83

ฉันใช้ System.Web.HttpUtility.JavaScriptStringEncode

string quoted = HttpUtility.JavaScriptStringEncode(input);

5
ฉันใช้สิ่งนี้เพื่อหลีกเลี่ยงสิ่งที่ขาดหายไปSystem.Web.Helpers.Json.Encodeใน VS2015 แต่ต้องใช้(input, true)พารามิเตอร์เพื่อรวมเครื่องหมายคำพูดจริงด้วย
lapo

นี่คือลิงค์ที่ขาดหายไปสำหรับฉัน
Jawid Hassim

52

สำหรับผู้ที่ใช้โครงการ Json.Net ยอดนิยมจาก Newtonsoft งานนั้นไม่สำคัญ:

using Newtonsoft.Json;

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

รหัสนี้พิมพ์:

"a \\ b"

นั่นคือค่าสตริงที่เป็นผลลัพธ์จะมีเครื่องหมายคำพูดเช่นเดียวกับเครื่องหมายแบ็กสแลชที่ใช้ Escape


2
ฉันไม่สามารถทำซ้ำวิธีนี้สำหรับการ deserializing เส้นทาง unc ที่เข้ารหัสและหลีกเลี่ยง เส้นทางของฉัน"WatchedPath": "\\\\myserver\\output"กลาย"\"\\\\\\\\myserver\\\\output\""เป็นสิ่งที่ยอมรับไม่ได้เลยทีเดียว
slestak

3
วิธีการข้างต้นไม่ได้มีไว้สำหรับ deserializing - rater ใช้เมื่อคุณต้องการสร้างข้อความ JSON ด้วยตนเองและคุณมีสตริง C # และจำเป็นต้องได้รับการแสดงที่เหมาะสมเป็นข้อความ
Dror Harari

@slestak ฉันคิดว่าฉันกำลังเผชิญกับปัญหาเดียวกับที่คุณอยู่ที่นี่ คุณพบวิธีแก้ปัญหาหรือไม่?
GP24

@ GP24 IIRC ฉันไม่ได้ ขออภัยฉันไม่มีข้อมูลเพิ่มเติม
slestak

ไม่มีปัญหาขอบคุณสำหรับการตอบกลับ ฉันทำสิ่งนี้หากช่วยคุณได้: yourAnnoyingDoubleEncodedString.Replace ("\\\\", "\\") แทนที่ ("\\\" "," \ "");
GP24

40

อาคารในคำตอบโดย Dejanสิ่งที่คุณสามารถทำได้คือการนำเข้าSystem.Web.Helpers.NET Framework ชุมนุมแล้วใช้ฟังก์ชั่นต่อไปนี้:

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

Substringโทรที่จำเป็นตั้งแต่Encodeล้อมรอบสตริงโดยอัตโนมัติด้วยคำพูดสอง


ดูเหมือนว่า System.Web.Helpers ไม่สามารถใช้งานได้ก่อนหน้านี้ Net 4.0
SerG

…และไม่มีอีกแล้วใน Visual Studio 2015 ด้วย
Lapo

5
นี่เป็นส่วนหนึ่งของ ASP.NET Web Pages 2.0 สามารถเพิ่มได้โดยใช้ NuGet มันไม่ได้เป็นส่วนหนึ่งของกรอบ
Murven

31

ใช่เพียงแค่เพิ่มฟังก์ชันต่อไปนี้ในคลาส Utils ของคุณหรือบางสิ่ง:

    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
ทำไมคุณต้องหนี/?
drzaus

ฉันรู้ว่านี่เป็นคำตอบเก่า ๆ และฉันดีใจที่เห็นสิ่งนี้ได้รับเนื่องจากฉันไม่ต้องการพึ่งพาไลบรารีภายนอกใด ๆ แต่ฉันสังเกตเห็นว่ากรณีเริ่มต้นสำหรับอักขระควบคุมจะส่งกลับ "\\ u000X" เสมอ ฉันเชื่อว่าคุณต้องร่ายถ่านก่อนถึง int ลองเปลี่ยนเป็นstring t = "000" + ((int)c).ToString("X");
ม.ค. ยกเลิก

กรณีเริ่มต้นที่ถูกต้องต้องเป็น:t = "000" + String.Format("{0:X}",(int) c);
daniatic

สิ่งที่เราต้องการจริงๆคือ " "\\u" + ((int)c).ToString("X4") (แม้ว่าฉันคิดว่าสองภาคต่อจะดีกว่านี้)
James Curran

16

ฉันใช้รหัสต่อไปนี้เพื่อหลีกเลี่ยงค่าสตริงสำหรับ json คุณต้องเพิ่ม "" "ของคุณในผลลัพธ์ของรหัสต่อไปนี้:

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
นี่ช่วยชีวิตฉันได้จริงๆ ขอบคุณมาก!
บ้านพัก

8
ห้ามใช้รหัสนี้ในการผลิต! การหลีกเลี่ยง JSON นี้ขาดอักขระพิเศษที่สำคัญ ดู: stackoverflow.com/a/33799784
vog

2
รหัสนี้ไม่ครอบคลุมกรณีพิเศษทั้งหมด ห้ามใช้ในการผลิต
Envil

2
สร้างวงล้อใหม่และแนะนำข้อบกพร่องบางอย่างในกรณีพิเศษไม่ใช่คำตอบที่ดี
Xilmiki

6

วิธีการที่นำเสนอนี้มีข้อผิดพลาด
ทำไมต้องเสี่ยงขนาดนั้นเมื่อคุณสามารถใช้ System.Web.HttpUtility.JavaScriptEncode

หากคุณใช้เฟรมเวิร์กที่ต่ำกว่าคุณสามารถคัดลอกและวางจากโมโนได้

ได้รับความอนุเคราะห์จาก 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();
    }

ซึ่งสามารถบีบอัดเป็นไฟล์

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

ฉันขอแนะนำให้ใช้ไลบรารีJSON.NET ที่กล่าวถึง แต่ถ้าคุณต้องหลีกเลี่ยงอักขระ Unicode (เช่น \ uXXXX) ในสตริง JSON ที่เป็นผลลัพธ์คุณอาจต้องทำเอง ลองดูที่แปลงสตริง Unicode สตริง ASCII หนีเช่น


4

ฉันทำการทดสอบความเร็วกับคำตอบเหล่านี้สำหรับสตริงยาวและสตริงสั้น รหัสของไคลฟ์แพทเทอร์สันได้รับรางวัลเล็กน้อยน่าจะเป็นเพราะคนอื่น ๆ กำลังพิจารณาตัวเลือกการทำให้เป็นอนุกรม นี่คือผลลัพธ์ของฉัน:

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

และนี่คือรหัสทดสอบ:

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


3

ฉันดีหนึ่งซับใช้ JsonConvert เหมือนที่คนอื่นมี แต่เพิ่มสตริงย่อยเพื่อลบเครื่องหมายคำพูดและแบ็กสแลชที่เพิ่มเข้ามา

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




0

ฉันเลือกที่จะใช้ System.Web.Script.Serialization.JavaScriptSerializerฉันเลือกที่จะใช้

ฉันมีคลาสตัวช่วยแบบคงที่ขนาดเล็กที่กำหนดไว้ดังนี้:

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

ในการจัดลำดับสิ่งที่ฉันเพิ่งโทร Serialization.ToJSON(itemToSerialize)

หากต้องการยกเลิกการเชื่อมต่อฉันเพียงแค่โทร Serialization.FromJSON<T>(jsonValueOfTypeT)

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.