我应该如何在JSON中转义字符串?

时间:2010-06-11 03:54:16

标签: java json escaping

手动创建JSON数据时,如何转义字符串字段?我应该使用像Apache Commons Lang StringEscapeUtilities.escapeHtmlStringEscapeUtilities.escapeXml这样的东西,还是应该使用java.net.URLEncoder

问题在于,当我使用SEU.escapeHtml时,它不会转义引号,当我将整个字符串包装在一对'中时,将生成格式错误的JSON。

18 个答案:

答案 0 :(得分:142)

理想情况下,找到您所用语言的JSON库,您可以将一些适当的数据结构提供给,让它担心如何逃避事情。它会让你更加理智。如果由于某种原因你没有使用你的语言库,你不想使用它(我不会建议这个¹),或者你正在编写一个JSON库,请继续阅读。

根据RFC逃脱它。 JSON非常宽松:必须逃脱的唯一字符是\"和控制代码(任何小于U + 0020的字符)。

这种转义结构特定于JSON。您需要一个特定于JSON的功能。所有转义都可以写成\uXXXX,其中XXXX是该字符的UTF-16代码单元¹。有一些快捷方式,例如\\,也可以使用。 (并且它们会产生更小更清晰的输出。)

有关详细信息,请参阅the RFC

¹JSON的转义是基于JS构建的,因此它使用\uXXXX,其中XXXX是UTF-16代码单元。对于BMP之外的代码点,这意味着编码代理对,这可能会有点毛茸茸。 (或者,您可以直接输出字符,因为JSON的编码是Unicode文本,并允许这些特定字符。)

答案 1 :(得分:51)

摘自Jettison

 public static String quote(String string) {
         if (string == null || string.length() == 0) {
             return "\"\"";
         }

         char         c = 0;
         int          i;
         int          len = string.length();
         StringBuilder sb = new StringBuilder(len + 4);
         String       t;

         sb.append('"');
         for (i = 0; i < len; i += 1) {
             c = string.charAt(i);
             switch (c) {
             case '\\':
             case '"':
                 sb.append('\\');
                 sb.append(c);
                 break;
             case '/':
 //                if (b == '<') {
                     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" + Integer.toHexString(c);
                     sb.append("\\u" + t.substring(t.length() - 4));
                 } else {
                     sb.append(c);
                 }
             }
         }
         sb.append('"');
         return sb.toString();
     }

答案 2 :(得分:35)

试试这个org.codehaus.jettison.json.JSONObject.quote("your string")

在此处下载:http://mvnrepository.com/artifact/org.codehaus.jettison/jettison

答案 3 :(得分:22)

org.json.simple.JSONObject.escape()转义引号,\,/,\ r,\ n,\ b,\ f,\ t和其他控制字符。它可用于转义JavaScript代码。

import org.json.simple.JSONObject;
String test =  JSONObject.escape("your string");

答案 4 :(得分:21)

Apache commons lang现在支持这个。只需确保您的类路径上有最新版本的Apache commons。你需要版本3.2 +

版本3.2的发行说明

LANG-797:将escape / unescapeJson添加到StringEscapeUtils。

答案 5 :(得分:9)

org.json.JSONObject quote(String data) 方法完成工作

import org.json.JSONObject;
String jsonEncodedString = JSONObject.quote(data);

摘自文档:

  

将数据编码为JSON字符串。 这适用于引号和任何必要的字符转义。 [...] Null将被解释为空字符串

答案 6 :(得分:6)

StringEscapeUtils.escapeJavaScript / StringEscapeUtils.escapeEcmaScript也可以做到这一点。

答案 7 :(得分:4)

如果您使用的是fastexml jackson,则可以使用以下内容: com.fasterxml.jackson.core.io.JsonStringEncoder.getInstance().quoteAsString(input)

如果您使用的是codehaus jackson,则可以使用以下命令: org.codehaus.jackson.io.JsonStringEncoder.getInstance().quoteAsString(input)

答案 8 :(得分:3)

不确定“手动创建json”是什么意思,但你可以使用类似gson(http://code.google.com/p/google-gson/)的东西,这会将你的HashMap,Array,String等转换为JSON值。我建议使用这个框架。

答案 9 :(得分:2)

在commons lang API中使用EscapeUtils类。

EscapeUtils.escapeJavaScript("Your JSON string");

答案 10 :(得分:2)

对于那些来这里寻找命令行解决方案的人,像我一样,cURL的--data-urlencode工作正常:

curl -G -v -s --data-urlencode 'query={"type" : "/music/artist"}' 'https://www.googleapis.com/freebase/v1/mqlread'

发送

GET /freebase/v1/mqlread?query=%7B%22type%22%20%3A%20%22%2Fmusic%2Fartist%22%7D HTTP/1.1
例如,

。可以将较大的JSON数据放入文件中,然后使用@语法指定要从中进行转义的数据。例如,如果

$ cat 1.json 
{
  "type": "/music/artist",
  "name": "The Police",
  "album": []
}

你要用

curl -G -v -s --data-urlencode query@1.json 'https://www.googleapis.com/freebase/v1/mqlread'

现在,这也是关于如何从命令行查询Freebase的教程: - )

答案 11 :(得分:2)

我没有花时间100%确定,但它对我的输入有效,足以被在线JSON验证器接受:

org.apache.velocity.tools.generic.EscapeTool.EscapeTool().java("input")

虽然看起来不比org.codehaus.jettison.json.JSONObject.quote("your string")

我只是在我的项目中使用了速度工具 - 我的“手动JSON”构建在速度模板中

答案 12 :(得分:1)

考虑MoshiJsonWriter课程。它有一个很棒的API,它可以将复制减少到最少,所有内容都可以很好地流式传输到字段,OutputStream等。

OutputStream os = ...;
JsonWriter json = new JsonWriter(Okio.buffer(Okio.sink(os)));
json.beginObject();
json.name("id").value(getId());
json.name("scores");
json.beginArray();
for (Double score : getScores()) {
  json.value(score);
}
json.endArray();
json.endObject();

如果你想要手中的字符串:

Buffer b = new Buffer(); // okio.Buffer
JsonWriter writer = new JsonWriter(b);
//...
String jsonString = b.readUtf8();

答案 13 :(得分:0)

这里显示实际实现的方法都是错误的。
我没有Java代码,但只是为了记录,你可以轻松转换这个C#代码:

礼貌的单一项目@ 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();
    }
}

答案 14 :(得分:0)

如果你需要在JSON字符串中转义JSON,请使用org.json.JSONObject.quote(“你需要转义的json字符串”)似乎运行良好

答案 15 :(得分:0)

使用\ uXXXX语法可以解决这个问题,谷歌UTF-16的标志名称,你可以找出XXXX,例如:utf-16双引号

答案 16 :(得分:0)

我认为2017年的最佳答案是使用javax.json API。使用javax.json.JsonBuilderFactory创建json对象,然后使用javax.json.JsonWriterFactory写出对象。非常好的建设者/作家组合。

答案 17 :(得分:0)

Apache commons-text现在有一个 StringEscapeUtils.escapeJson(String)