如何转义 JSON 字符串?

Posted

技术标签:

【中文标题】如何转义 JSON 字符串?【英文标题】:How to escape JSON string? 【发布时间】:2009-08-06 23:40:42 【问题描述】:

是否有任何类/函数可用于轻松进行 JSON 转义?我宁愿不用自己写。

【问题讨论】:

JsonConvert.ToString() 为我工作。 @MartinLottering 谢谢!!!我一直在寻找一种将 json 转换为格式化字符串的方法。以下答案均无效,但确实有效。 【参考方案1】:

我用System.Web.HttpUtility.javascriptStringEncode

string quoted = HttpUtility.JavaScriptStringEncode(input);

【讨论】:

我用它来避免 VS2015 中缺少 System.Web.Helpers.Json.Encode,但它需要 (input, true) 参数来包含实际的引号。 这是我缺少的链接 我注意到这会将单引号 ' 编码为 \u0027。然而,单引号在 JSON 字符串中是有效的。【参考方案2】:

对于那些使用 Newtonsoft 非常流行的 Json.Net 项目的人来说,任务是微不足道的:

using Newtonsoft.Json;

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

此代码打印:

"a\\b"

也就是说,生成的字符串值包含引号以及转义的反斜杠。

【讨论】:

我无法重现此方法来反序列化编码和转义的 unc 路径。我的路径"WatchedPath": "\\\\myserver\\output" 变成了"\"\\\\\\\\myserver\\\\output\"",这是非常不可接受的。 上述方法不适用于反序列化 - 当您想要手动创建 JSON 文本并且您有一个 C# 字符串并且需要将其正确表示为文本时使用它。 @slestak,我想我遇到了和你一样的问题。你找到解决办法了吗? @GP24 IIRC,我没有。抱歉,我没有更多信息。 没问题,谢谢回复。如果对您有帮助,我会这样做: yourAnnoyingDoubleEncodedString.Replace("\\\\", "\\").Replace("\\\"", "\"");【参考方案3】:

在the answer by Dejan的基础上,你可以做的是import System.Web.Helpers .NET Framework assembly,然后使用如下函数:

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 之前不可用 ……在 Visual Studio 2015 中也没有了。 这是 ASP.NET 网页 2.0 的一部分。它可以使用 NuGet 添加。它不是框架的一部分。【参考方案4】:

是的,只需将以下函数添加到您的 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();
    

【讨论】:

为什么要转义/ 我知道这是一个旧的答案,我很高兴看到这是因为我不想依赖任何外部库,但我注意到控制字符的默认情况将总是返回“\\u000X”。我相信您需要先将 char 转换为 int。考虑将其替换为string t = "000" + ((int)c).ToString("X"); 正确的默认大小写必须是:t = "000" + String.Format("0:X",(int) c); 我们真正想要的是“"\\u" + ((int)c).ToString("X4")(虽然我觉得两个Appends会更好)【参考方案5】:

我使用以下代码来转义 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("01", BACK_SLASH, SLASH);
                break;

            case BACK_SLASH:
                output.AppendFormat("00", BACK_SLASH);
                break;

            case DBL_QUOTE:
                output.AppendFormat("01",BACK_SLASH,DBL_QUOTE);
                break;

            default:
                output.Append(c);
                break;
        
    

    return output.ToString();

【讨论】:

这真的拯救了我的一天。非常感谢! 请勿在生产环境中使用此代码!这种 JSON 转义遗漏了重要的特殊字符。见:***.com/a/33799784 这段代码没有涵盖所有的特殊情况。不要在生产中使用。 重新发明***,并在特殊情况下引入一些错误,不是一个好的答案【参考方案6】:

在 .Net Core 3+ 和 .Net 5+ 中:

string escapedJsonString = JsonEncodedText.Encode(jsonString);

【讨论】:

您需要提及的是,默认情况下这不会进行微不足道的转义,结果可能比您想要的要转义得多。例如,引号、三角括号和许多字母将被转换为 unicode 字符,并且只有在您在另一端取消转义时才能使用。【参考方案7】:

这里提供的方法有问题。 当您可以使用 System.Web.HttpUtility.JavaScriptEncode 时,为什么要冒险这么远?

如果你在较低的框架上,你可以从单声道复制粘贴它

感谢单一项目@ 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("\\u0: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();
    

【讨论】:

这也将转义三角括号。对于 html 中的 JS 很重要,但对于 JSON 编码本身并不重要。【参考方案8】:

我还建议使用提到的JSON.NET 库,但如果您必须在生成的 JSON 字符串中转义 unicode 字符(例如 \uXXXX 格式),您可能必须自己做。以Converting Unicode strings to escaped ascii string 为例。

【讨论】:

【参考方案9】:

我针对长字符串和短字符串对其中一些答案进行了速度测试。 Clive Paterson 的code 赢了很多,大概是因为其他人正在考虑序列化选项。这是我的结果:

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

【讨论】:

【参考方案10】:

我很好的单线,像其他人一样使用 JsonConvert,但添加了子字符串以删除添加的引号和反斜杠。

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

【讨论】:

我认为你的意思是 var escapedJsonString = JsonConvert.ToString(JsonString).Substring(1, JsonString.Length); - 否则你从字符串的末尾砍掉 2 个字符。请记住,\" 是原始长度的附加字符。【参考方案11】:

System.Web.Helpers.Json.Encode(...) 怎么样(见http://msdn.microsoft.com/en-us/library/system.web.helpers.json.encode(v=vs.111).aspx)?

【讨论】:

【参考方案12】:
String.Format("X", c);

那只是输出:X

试试这个:

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

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

【讨论】:

【参考方案13】:

Codeplex 有一个 Json 库

【讨论】:

【参考方案14】:

我选择使用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&lt;T&gt;(jsonValueOfTypeT)

【讨论】:

以上是关于如何转义 JSON 字符串?的主要内容,如果未能解决你的问题,请参考以下文章

如何转义 JSON 字符串?

如何在 JSON 对象中转换转义的 JSON 字符串?

idea还原转义json

Java:JSON字符串在Java中已经转义过了,如何再拼接函数呢

js解析json字符串报错解决方案(带有转义字符的json字符串)

Spark - 如何将 JSON 转义的字符串字段解析为 DataFrames 中的 JSON 对象?