10

我正在用 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('\0x05');
mystr.push_back('\0xd9');

或者我应该用一个库来解释这两个字符,iconv并将 UTF-8 编码的结果存储在我的字符串中?

我应该使用 astd::wstring来存储所有字符吗?那么在 *NIX 操作系统上wchar_t4 字节长的地方是什么?

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

4

2 回答 2

15

经过一番挖掘并感谢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解释如何处理\uXXXXJSON 字符串中的这些值:

任何字符都可以转义。如果字符在基本
多语言平面(U+0000 到 U+FFFF),那么它可以
表示为六个字符序列:一个反斜线,后跟
小写字母 u,后跟四个十六进制数字,
编码字符的代码点。十六进制字母 A 到
F 可以是大写或小写。因此,例如,一个
只包含一个反斜线字符的字符串可以表示为
“\u005C”。

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

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

希望这可以帮助。

于 2012-10-28T10:00:57.267 回答
2

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

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

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

于 2012-10-28T08:43:01.137 回答