从C++文件中读取和打印 UTF-8 符号



我遇到了一个问题,在互联网上找不到答案。尽管我发现了许多类似的问题,但没有一个答案对我有用。我在 Windows 10 上使用 Visual Studio 2015。

所以我的部分代码是:

wstring books[50];
wstring authors[50];
wstring genres[50];
wstring takenBy[50];
wstring additional;
bool taken[50];
_setmode(_fileno(stdout), _O_U8TEXT);
wifstream fd("bookList.txt");
i = 0;
while (!fd.eof())
{
getline(fd, books[i]);
getline(fd, authors[i]);
getline(fd, genres[i]);
getline(fd, takenBy[i]);
fd >> taken[i];
getline(fd, additional);
i++;
}

我需要的是用C++读取以 UTF-8 编码的文本文件。但是,当我阅读文件时,这些宽字符串发生了变化,当我打印它们时,输出文本完全不同。

输入:

ąčę

输出:

ÄÄÄ


如何避免它并正确阅读文本?

UTF-8 (可能(不在宽字符串中。随时随地阅读有关 UTF-8 的信息。UTF-8 使用8 位字节(有时是几个字节(对 Unicode 字符进行编码。因此,在C++中,unicode 字符是从 1 到 6 个字节的序列中解析的(即char-s(。

您需要一些 UTF-8 解析器,而 C11 或 C++11 标准不提供任何解析器。所以你需要一些外部库。查看libunistring(这是一个简单的C UTF-8解析库(或其他东西(Qt,POCO,Glib,ICU,...(。您可以决定解析 UTF-8 并将其转换为宽 UTF-32(使用u32stringchar32_t(并向后,或者您最好决定在内部使用 UTF-8(使用std::stringchar

(因此,您将解析和打印char-s 的序列(使用 UTF-8 编码(,您的程序将使用纯std::string-s 和纯char-s(不是std::wstringwchar_t(,但处理UTF-8 序列......

这很容易使用Boost.Spirit:

#define BOOST_SPIRIT_UNICODE
#include <boost/spirit/include/qi.hpp>
#include <iostream>
#include <string>
using namespace boost::spirit;
int main()
{
std::string in("ąčę");
std::string out;
qi::parse(in.begin(), in.end(), +unicode::char_, out);
std::cout << out << std::endl;
}

下面的示例读取元组序列(书籍、作者、takenBy(:

#define BOOST_SPIRIT_UNICODE
#include <boost/spirit/include/qi.hpp>
#include <boost/fusion/adapted/std_tuple.hpp>
#include <iostream>
#include <string>
#include <tuple>
#include <vector>
using namespace boost::spirit;
int main()
{
std::string in("Book_1nAuthors_1nTakenBy_1n"
"Book ąčęnAuthors_2nTakenBy_2n");
std::vector<
std::tuple<
std::string, /* book */
std::string, /* authors */
std::string  /* takenBy */
> 
> out;
auto ok = qi::parse(in.begin(), in.end(),
*(
+(unicode::char_ - qi::eol) >> qi::eol /* book */
>> +(unicode::char_ - qi::eol) >> qi::eol /* authors */
>> +(unicode::char_ - qi::eol) >> qi::eol /* takenBy */
),
out);
if(ok)
{
for(auto& entry : out)
{
std::string book, authors, takenBy;
std::tie(book, authors, takenBy) = entry;
std::cout << "book: "    << book    << std::endl
<< "authors: " << authors << std::endl
<< "takenBy: " << takenBy << std::endl;
}
}
}

这只是一个使用std::tuple和未命名解析器的演示,这是qi::parse的第三个参数。您可以使用结构而不是元组来表示书籍、作者、流派等。未命名的解析器可以替换为语法,您可以将文件的内容读入字符串以传递给qi::parse

最新更新