rapidjson icon indicating copy to clipboard operation
rapidjson copied to clipboard

JSON字符串包含生僻中文字符无法解析

Open muzipeng718 opened this issue 5 years ago • 27 comments

JSON字符串包含生僻中文字符无法解析,正常汉字可以解析

muzipeng718 avatar Jun 03 '20 13:06 muzipeng718

请给一个JSON文件

miloyip avatar Jun 04 '20 02:06 miloyip

例如中文字符:“賊”,当addmember中存在这个字符时,获取序列化之后的json字符串中会出现多余的\\。

caomfan avatar Jul 13 '20 09:07 caomfan

不能重现:

in.json

{"賊":1}

a.cpp:

#include "rapidjson/document.h"
#include "rapidjson/writer.h"
#include "rapidjson/filereadstream.h"
#include "rapidjson/filewritestream.h"

using namespace rapidjson;

int main() {
    Document d;

    {
        FILE* fp = fopen("in.json", "r");
        char buffer[256];
        FileReadStream frs(fp, buffer, sizeof(buffer));
        d.ParseStream(frs);
        fclose(fp);
    }

    {
        FILE* fp = fopen("out.json", "w");
        char buffer[256];
        FileWriteStream fws(fp, buffer, sizeof(buffer));
        Writer<FileWriteStream> writer(fws);
        d.Accept(writer);
        fclose(fp);
    }
}
$g++ -I ~/github/rapidjson/include a.cpp && ./a.out && cat out.json
{"賊":1}

Archive.zip

miloyip avatar Jul 13 '20 11:07 miloyip

请给一个JSON文件

{"CMD":123,"REQ":{"Head":{"UserID":"ew2121","PrjID":"32dds","StationKey":"3422ddsddsd","No":1},"ID":"1","Prop":{"Name":"昛昜昞昇","Lang":"CCC","CanvasSize":"A4"}}} 解析上述字符串根据“UserID”、“PrjID”等都无法拿到对应的值,字符串是uft-8转多字节

muzipeng718 avatar Jul 13 '20 14:07 muzipeng718

#include <iostream>
#include "rapidjson/rapidjson.h"
#include "rapidjson/document.h"
#include "rapidjson/writer.h"

using namespace std;
using namespace rapidjson;

int main()
{
    Document d;
    Document::AllocatorType& allocator = d.GetAllocator();
    Value root(kObjectType);
    root.AddMember("content", "賊", allocator);
    StringBuffer buffer;
    Writer<StringBuffer> writer(buffer);
    root.Accept(writer);
    string json_content = buffer.GetString();

    std::cout <<json_content.c_str()<<std::endl;
    return 0;
}

print: {"content":"賊\"}

打印出来的字符串后面会多一个\,类似的字符还有:忎,忈,朲,芢,朲,銋,姙,鈓,鵀,絍 ,等等。

caomfan avatar Jul 14 '20 09:07 caomfan

@caomfan 你的 C++ 源文件是不是 UTF-8?

miloyip avatar Jul 14 '20 09:07 miloyip

@miloyip 是的,有没有比较好的解决方式

caomfan avatar Jul 14 '20 09:07 caomfan

@caomfan 我在这机器上不能重现

 g++ -I ~/github/rapidjson/include a.cpp && ./a.out                
{"content":"賊"}

miloyip avatar Jul 14 '20 09:07 miloyip

@caomfan 试改一下输出,看看结果?

    for (size_t i = 0; i < json_content.size(); i++)
        std::cout << std::hex << (unsigned)(unsigned char)json_content[i] << " " << json_content[i] << std::endl;
7b {
22 "
63 c
6f o
6e n
74 t
65 e
6e n
74 t
22 "
3a :
22 "
e8 ?
b3 ?
8a ?
22 "
7d }

賊的 UTF-8 确实是 0xE8 0xB3 0x8A

miloyip avatar Jul 14 '20 10:07 miloyip

@miloyip 我在win10,IDE是VisualStudio 2017,,输出的结果如下: 7b { 22 " 63 c 6f o 6e n 74 t 65 e 6e n 74 t 22 " 3a : 22 " d9 5c
5c
22 " 7d }

caomfan avatar Jul 14 '20 10:07 caomfan

试试 json_content = "賊";

miloyip avatar Jul 14 '20 10:07 miloyip

输出 d9,5c

caomfan avatar Jul 14 '20 10:07 caomfan

使用rapidjson时后面会再加一个5c

caomfan avatar Jul 14 '20 10:07 caomfan

D95C 是 GB 码⋯⋯不是 UTF-8

miloyip avatar Jul 14 '20 10:07 miloyip

因为 5C 是 \,假设它是 UTF-8 的话,写出来需要转义成 \\

miloyip avatar Jul 14 '20 10:07 miloyip

但是c++源文件默认编码格式确实是UTF-8.

caomfan avatar Jul 14 '20 10:07 caomfan

那应该是 VC 的问题吧。打印出来的字面量都是 GB 码的,那和 RapidJSON 没有关系。

试一下用 C++11 的 u8 prefix 能不解决你的问题? https://en.cppreference.com/w/cpp/language/string_literal

miloyip avatar Jul 14 '20 10:07 miloyip

https://docs.microsoft.com/zh-cn/cpp/preprocessor/execution-character-set?view=vs-2019

miloyip avatar Jul 14 '20 10:07 miloyip

@miloyip 谢谢,还是不能正常转义。我试试其它方法。

caomfan avatar Jul 14 '20 10:07 caomfan

@miloyip 我找到了一种比较好的方式来解决这个问题,先将字符做GBKToUTF8处理,之后再将结果UTF8ToGBK。

caomfan avatar Jul 17 '20 08:07 caomfan

这是可以的

miloyip avatar Jul 17 '20 09:07 miloyip

Windows平台确实存在这个问题。我的程序中,VC++编译的用RapidJSON读取UTF8的非生僻字中文后写入cout就会导致乱码。目前我是通过启用区域设置里面的“使用Unicode UTF-8提供全球语言支持”的选项来解决了问题,不知道有没有更好的办法让Windows在中文区域使用UTF8。

execution_char_set指令,实测无效。

RigoLigoRLC avatar Jul 22 '20 15:07 RigoLigoRLC

GB 编码的json字串遇到生僻字Parse 就会出错 但是项目输入的汉字都是GB编码 如果转UTF-8再转回来 改起来就非常麻烦

rexshao avatar Aug 09 '20 02:08 rexshao

GB 编码的json字串遇到生僻字Parse 就会出错 但是项目输入的汉字都是GB编码 如果转UTF-8再转回来 改起来就非常麻烦

RapidJSON 只支持 UTF-8, UTF-16, UTF-32 和 ASCII 的 JSON,暂不支持其他编码。 JSON 标准也是以 Unicode 为基础。

miloyip avatar Aug 10 '20 04:08 miloyip

{"SUB_NAME":"鍟嗗搧閲囪喘-閲囪喘鍛?,"SPECTATORID":""} 这是后端给的数据,utf8格式, utf8tounicode的时候,正常显示,并且可以解析,但是问题是 如果使用gbktoutf8会不会也有类似的?之类 影响解析

a1726015841 avatar Jun 30 '21 10:06 a1726015841

Just pass option /utf-8 to cl.exe, and use root.AddMember("content", u8"賊"s, allocator); // before C++20. See this.

  1. If you are using VS IDE, try this.
  2. With CMake, try add_compile_options($<$<BOOL:${MSVC}>:/utf-8) or target_compile_options(main PUBLIC $<$<BOOL:${MSVC}>:/utf-8)

Arlen-LT avatar Aug 17 '23 09:08 Arlen-LT