【问题标题】:Error passing Unicode string through JSONObject通过 JSONObject 传递 Unicode 字符串时出错
【发布时间】:2015-06-08 06:50:31
【问题描述】:

我必须将 unicode 字符串传递给 JSONObject。

JSONObject json = new JSONObject("{\"One\":\"\\ud83c\\udf45\\ud83c\\udf46\"}");
json.put("Two", "\ud83c\udf45\ud83c\udf46");
System.out.println(json.toString());

但我有这个:

{"One":"????????","Two":"????????"}

我想要这个:

{"One":"\ud83c\udf45\ud83c\udf46","Two":"\ud83c\udf45\ud83c\udf46"}

【问题讨论】:

  • 你试过转义你的字符串吗? json.put("Two", "\\ud83c\\udf45\\ud83c\\udf46");
  • 我有这个:{"One":"????????","Two":"\\ud83c\\udf45\\ud83c\\udf46"}
  • @LutzHorn:阅读JSON spec,第 9 节...
  • @LutzHorn: 如果码位在基本多语言平面(U+0000 到 U+FFFF),那么它可以表示为一个六字符序列:一个反斜线,后跟小写字母 u,后跟四个对代码点进行编码的十六进制数字...要转义不在基本多语言平面中的代码点,字符表示为十二个字符序列,编码UTF-16 代理对。因此,例如,仅包含 G 谱号字符 (U+1D11E) 的字符串可以表示为“\uD834\uDD1E”。
  • @LutzHorn:我的 cmets 会告诉你它们是有效的 Unicode 字符。根据我引用的 JSON 规范第 9 节,它们被编码为 UTF-16 代理对。 \ud83c\udf45 代表U+1F345 TOMATO\ud83c\udf46 代表U+1F346 AUBERGINE

标签: java unicode jsonobject


【解决方案1】:

系统按设计运行。您只是没有考虑到 JSON 并不要求大多数 Unicode 字符以\uXXXX 格式格式化。某些转义字符必须采用\X格式,控制字符必须采用\uXXXX格式,但任何其他字符可能 > 采用\uXXXX 格式,但不是必需。您显示的字符不属于这些范围,这就是toString() 未将它们编码为\uXXXX 格式的原因。

当您调用 new JSONObject(String) 时,它会将输入字符串解码为实际的 Unicode 字符串,就好像您已经这样做了:

JSONObject json = new JSONObject();
json.put("One", "\ud83c\udf45\ud83c\udf46");

这很好。您希望JSONObject 在内部保存未转义的 Unicode 数据。

您被绊倒的地方是JSONObject.toString() 没有将您的特定Unicode 字符格式化为\uXXXX 格式。这是完全有效的 JSON,但不是您希望它们被格式化的方式(为什么要以这种方式格式化它们?)。

查看 Java 的 JSONStringer 类(它实现了 JSONObject.toString())的源代码,发现它仅以 \uXXXX 格式格式化非保留控制字符

要执行您的要求,您必须在调用 JSONObject.toString() 以正常格式化保留字符和 ASCII 字符后,根据需要手动格式化 Unicode 字符,例如:

JSONObject json = new JSONObject("{\"One\":\"\\ud83c\\udf45\\ud83c\\udf46\"}");
// decodes as if json.put("One", "\ud83c\udf45\ud83c\udf46")
// or json.put("One", "??") were called directly ...

json.put("Two", "\ud83c\udf45\ud83c\udf46");
// same as calling json.put("Two", "??") ...

String s = json.toString();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < s.length(); ++i)
{
    char ch = s.charAt(i);
    if (ch >= 0x7F)
        sb.append(String.format("\\u%04x", (int) ch));
    else
        sb.append(ch);
}

System.out.println(sb.toString());
// outputs '{"One":"\ud83c\udf45\ud83c\udf46","Two":"\ud83c\udf45\ud83c\udf46"}' as expected ...

【讨论】:

    【解决方案2】:

    这样做的一种方法是:

    json.put("Two", "\\u" + "d83c" + "\\u" + "df45" + ...);
    

    当您尝试打印 JSON 时,这将打印字符串文字 \ud83c\udf45

    【讨论】:

    • 这与使用 json.put("Two", "\\ud83c\\udf45..."); 没有什么不同,因为连接发生在调用 put() 之前。
    • 这告诉库插入文字值\ud83c,其中\必须在JSON中转义。
    猜你喜欢
    • 2015-02-12
    • 1970-01-01
    • 1970-01-01
    • 2015-12-25
    • 2023-03-07
    • 1970-01-01
    • 2020-03-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多