如何处理JSON字符串中的unicode值

How to handle unicode values in JSON strings?

本文关键字:字符串 unicode JSON 何处理 处理      更新时间:2023-10-16

我正在用C++编写一个JSON解析器,在解析JSON字符串时遇到了一个问题:

JSON规范规定JSON字符串可以包含以下形式的unicode字符:

"here comes a unicode character: u05d9 !"

我的JSON解析器试图将JSON字符串映射到std::string,所以通常情况下,JSON字符串的一个字符变成std::string的一个字符串。然而,对于那些unicode字符,我真的不知道该怎么办:

我应该像这样把原始字节值放在std::string中吗:

std::string mystr;
mystr.push_back('x05');
mystr.push_back('xd9');

还是应该使用iconv这样的库来解释这两个字符,并将UTF-8编码的结果存储在字符串中?

我应该使用std::wstring来存储所有字符吗?那么在wchar_t为4字节长的*NIX操作系统上呢?

我感觉到我的解决方案有问题,但我不明白是什么。在这种情况下我该怎么办?

经过一番挖掘,感谢H2CO3的评论和Philipp的评论,我终于明白了这应该是如何工作的:

阅读RFC4627,章节3. Encoding:

  1. 编码

    JSON文本应采用Unicode编码。默认编码为
    UTF-8。

    由于JSON文本的前两个字符将始终是ASCII字符[RFC0020],可以通过查看前四个八位字节中的空模式来确定八位字节
    流是UTF-8、UTF-16(BE或LE)还是UTF-32(BE或LE])。

    00 00 00 xx  UTF-32BE
    00 xx 00 xx  UTF-16BE
    xx 00 00 00  UTF-32LE
    xx 00 xx 00  UTF-16LE
    xx xx xx xx  UTF-8
    

因此,JSON八位字节流似乎可以用UTF-8、UTF-16或UTF-32编码(最后两种都是be或LE变体)。

一旦明确了这一点,Section 2.5. Strings将解释如何处理JSON字符串中的uXXXX值:

任何字符都可以转义。如果该字符位于基本
多语言平面(U+0000到U+FFFF)中,则它可以被
表示为六个字符序列:一个反向solidus,后跟小写字母U,后跟四个十六进制数字,
对字符的代码点进行编码。十六进制字母A到
F可以是大写或小写。因此,例如,一个仅包含
一个反向solidus字符的字符串可以表示为
"\u005C"。

对不在基本多语言平面中的字符有更完整的解释。

转义不在基本多语言中的扩展字符平面上,字符表示为十二个字符的序列,
编码UTF-16代理项对。因此,例如,仅包含G谱号字符(U+1D11E)的字符串
可以表示为
"\uD834\uDD1E"。

希望这能有所帮助。

如果我是你,我会使用std::string只存储UTF-8和UTF-8。如果传入的JSON文本不包含任何\uXXXX序列,则std::string可以按原样使用,逐字节使用,无需任何转换。

当您解析\uXXXX时,您可以简单地对其进行解码并将其转换为UTF-8,从而有效地将其视为真正的UTF-8字符——这是大多数JSON解析器正在做的事情(当然是libjson)。

当然,使用这种方法读取带有\uXXXX的JSON并立即使用库将其转储回可能会丢失\uXXXX序列,并将其替换为真正的UTF-8表示,但谁真的在乎呢?最终,最终结果仍然完全相同。