用C++阅读和转换JSON文件中的西里尔Unicode字符

yxyvkwin  于 2023-03-20  发布在  其他
关注(0)|答案(1)|浏览(151)

我有一个JSON文件,包含以下内容(例如):

{
    "excel_filepath": "excel_file.xlsx",
    "line_length": 5.0,
    "record_frequency": 2.5,
    "report_file_name": "\u041f\u0421 \u041f\u0440\u043e\u043c\u0437\u043e\u043d\u0430 - \u041f\u0421 \u041f\u043e\u0433\u043e\u0440\u0435\u043b\u043e\u0432\u043e (\u0426.1)",
    "line_type": 1,
}

此JSON文件由Python脚本生成。
为了阅读JSON文件,我使用<nlohmann/json.hpp>库(我发现它对我的情况很简单):

using json = nlohmann::json;

std::ifstream f("temp_data.json");
json data = json::parse(f);

我要做的是读取"report_file_name"值,并创建一个简单的.txt文件,命名为report_file_name键的值,它以Unicode存储,如您所见。
我正在努力做的事情如下:

_setmode(_fileno(stdout), _O_U16TEXT);
const locale utf8_locale = locale(locale(), new codecvt_utf8<wchar_t>());

string report_file_name = data["report_file_name"];
    
for (auto unicode_char : report_file_name) 
{
    wcout << typeid(unicode_char).name() << ": " << unicode_char << endl;
}

wofstream report_file(report_file_name + L".txt");
report_file.imbue(utf8_locale);

这将给出如下输出:

char: Ð  
char:  
char: Ð  
char: ¡  
char:  
char: Ð  
char:  
char: Ñ  
char:  
char: Ð  
char: ¾
... and so on

我必须指出,我设法将西里尔字母写入报告文件。有趣的是,当我这样做时:

wcout << L"\u041f\u0421" << endl;

它可以正确地打印出西里尔字母(ПС)。另外,使用以下代码创建具有西里尔名称的报告.txt文件也没有问题:

wofstream report_file(L"Отчет.txt"); // fine!

我做错了什么吗?我使用的是Windows 10,MVS 2022与C++17标准。如果这是有帮助的。

svmlkihl

svmlkihl1#

根据nlohmann::json的文档:
https://github.com/nlohmann/json#character-encoding
字符编码
库支持Unicode输入,如下所示:

  • 仅支持UTF-8编码的输入,根据RFC 8259,这是JSON的默认编码。
  • 可以分析std::u16stringstd::u32string,分别采用UTF-16和UTF-32编码。从文件或其他输入容器阅读时不支持这些编码。
  • 不支持其他编码(如Latin-1或ISO 8859-1),这些编码将产生分析或序列化错误。
  • Unicode非字符不会被库替换。
  • 无效的代理(例如\uDEAD等不完整的对)将产生解析错误。
    ***存储在库中的字符串是UTF-8编码的。**使用默认字符串类型(std::string)时,请注意其length/size函数返回的是存储的字节数,而不是字符或字形数。
  • 在库中存储具有不同编码的字符串时,调用dump()可能会引发异常,除非将json::error_handler_t::replacejson::error_handler_t::ignore用作错误处理程序。
    *要存储宽字符串(例如std::wstring),您需要在之前将其转换为UTF-8编码的std::string,请参见示例。

因此,在您的情况下,您的report_file_name字符串是UTF-8编码的std::string,您需要将其解码为std::wstring(Windows上为UTF-16,其他平台上为UTF-32),然后才能将其用于std::wofstream,例如:

std::wstring utf8_to_wstr(const std::string &uf8)
{
    // there are many questions on StackOverflow about how to do this conversion.
    // You can use the Win32 MultiByteToWideChar() API, or std::wstring_convert
    // with std::std::codecvt_utf8/_utf16, or a 3rd party Unicode library such as
    // ICU or iconv...
}

...

wstring report_file_name = utf8_to_wstr(data["report_file_name"]);

相关问题