如何转义 JSON 字符串?

是否有类/函数可用于简单的 JSON 转义? 我宁愿不用自己编写。

194615 次浏览

科迪克斯有个 Json 图书馆

我还建议使用上面提到的 JSON.NET库,但是如果必须在生成的 JSON 字符串中转义 unicode 字符(例如 uXXXX 格式) ,则可能必须自己转义。以 将 Unicode 字符串转换为转义 ascii 字符串为例。

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

我使用了以下代码来转义 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();
}
String.Format("X", c);

输出: X

试试这个:

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


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

德扬的回答的基础上,你可以做的是 导入 System.Web.Helpers.NETFramework 程序集,然后使用以下函数:

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

Substring调用是必需的,因为 Encode会自动用双引号包围字符串。

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

using Newtonsoft.Json;


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

这个代码显示:

“ A B”

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

我用 System.Web.HttpUtility.JavaScriptStringEncode

string quoted = HttpUtility.JavaScriptStringEncode(input);

我对其中一些答案进行了长线和短线的速度测试。Clive Paterson 的 密码赢了不少,大概是因为其他人考虑了序列化选项。以下是我的结果:

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

这里提供的方法是错误的。
既然可以使用 System.Web.HttpUtility.JavaScriptEncode,为什么还要冒这么大的风险呢?

如果你在一个较低的框架,你可以只是复制粘贴它从 mono

承蒙单一项目的好意@ Https://github.com/mono/mono/blob/master/mcs/class/System

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

我很好的一行程序,像其他人一样使用了 JsonConvert,但是添加了子字符串来删除添加的引号和反斜杠。

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

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

string escapedJsonString = JsonEncodedText.Encode(jsonString);

我选择使用 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)