【问题标题】:Reading and printing UTF-8 symbols from a file in C++从 C++ 文件中读取和打印 UTF-8 符号
【发布时间】:2017-07-02 16:07:48
【问题描述】:

我遇到了一个问题,但在互联网上找不到答案。尽管我发现了许多类似的问题,但没有一个答案对我有用。我在 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 编码的文本文件。但是,当我读取文件时,那些宽字符串发生了变化,当我打印它们时,输出文本完全不同。

输入:

ąčę

输出:

阿耶


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

【问题讨论】:

  • 为了避免我们注定要简单地重复所有“对您不起作用”的答案,也许您可​​以详细说明为什么现有解决方案不适用?
  • @LightnessRacesinOrbit 好吧,正如我所说,我需要从文件中获取并打印 UTF-8 字符,但是当我尝试在其他地方给出的答案和建议时,它们要么不起作用根本没有做我需要做的事情,例如,正如我已经写过的,字符串会丢失 UTF-8 字符,我想知道如何避免这种丢失。
  • 更新您的问题,请不要发表评论。你能说明你在哪个平台上运行吗? Unicode 仍然有一些平台依赖性。
  • 如果您使用的是 Windows 控制台,请参阅stackoverflow.com/questions/388490/…
  • 这是OT,但请注意while (!fd.eof())可能会导致unexpected results

标签: c++ windows utf-8


【解决方案1】:

UTF-8 is(可能)不在宽字符串中。阅读UTF-8 everywhere。 UTF-8 使用 8 位字节(有时是 几个)来编码 Unicode 字符。所以在 C++ 中,一个 unicode 字符是从 1 到 6 个字节的序列中解析出来的(即char-s)。

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

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

【讨论】:

  • 阅读这句话真是令人沮丧C11 or C++11 standards don't provide any
【解决方案2】:

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;
}

下面的例子读取一个元组序列(书、作者、takeBy):

#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_1\nAuthors_1\nTakenBy_1\n"\
                   "Book ąčę\nAuthors_2\nTakenBy_2\n");
    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 的第三个参数。您可以使用struct 代替元组来表示书籍、作者、流派 等。未命名的解析器可以替换为grammar,您可以将文件内容读入一个要传递给qi::parse 的字符串。

【讨论】:

    猜你喜欢
    • 2011-12-23
    • 2013-03-06
    • 2020-06-04
    • 2015-01-17
    • 1970-01-01
    • 1970-01-01
    • 2011-01-08
    • 1970-01-01
    • 2017-09-06
    相关资源
    最近更新 更多