【问题标题】:Read unicode file with special characters using std::wifstream使用 std::wifstream 读取带有特殊字符的 unicode 文件
【发布时间】:2021-08-05 16:27:48
【问题描述】:

在Linux环境下,我有一段读取unicode文件的代码,类似如下图。

但是,无法正确处理特殊字符(如丹麦字母 æ、ø 和 å)。对于“abcæøåabc”行,输出只是“abc”。使用调试器我可以看到wline 的内容也只有a\000b\000c\000

#include <fstream>
#include <string>

std::wifstream wif("myfile.txt");
if (wif.is_open())
{
    //set proper position compared to byteorder
    wif.seekg(2, std::ios::beg);
    std::wstring wline;

    while (wif.good())
    {
        std::getline(wif, wline);
        if (!wif.eof())
        {
            std::wstring convert;
            for (auto c : wline)
            {
                if (c != '\0')
                convert += c;
            }
        }
    }
}
wif.close();

谁能告诉我如何让它阅读整行?

感谢和问候

【问题讨论】:

  • 对文件进行十六进制转储,它包含什么?
  • 我得到了以下十六进制转储 0000000: fffe 6100 6200 6300 e600 f800 e500 6100 ..a.b.c.......a. 0000010: 6200 6300 0d00 0a00 b.c..... 即使字符本身没有显示在上面的输出中,至少十六进制值似乎是正确的 - fffe 用于 utf-16-le 编码,@987654327 @ 代表 æ,f800 代表 ø,e500 代表 æ。
  • 您需要使用带有 UTF-16LE 语言环境的imbue 来指示文件的格式。我试图为您找到相关指南,但找不到。
  • @MarkRansom: en.cppreference.com/w/cpp/locale/codecvt_utf16 显示了一个示例。

标签: c++ linux unicode


【解决方案1】:

您必须使用imbue() 方法告诉wifstream 该文件被编码为UTF-16,并让它为您消耗BOM。您不必手动 seekg() 越过 BOM。例如:

#include <fstream>
#include <string>
#include <locale>
#include <codecvt>

// open as a byte stream
std::wifstream wif("myfile.txt", std::ios::binary);
if (wif.is_open())
{
    // apply BOM-sensitive UTF-16 facet
    wif.imbue(std::locale(wif.getloc(), new std::codecvt_utf16<wchar_t, 0x10ffff, std::consume_header>));

    std::wstring wline;
    while (std::getline(wif, wline))
    {
        std::wstring convert;
        for (auto c : wline)
        {
            if (c != L'\0')
                convert += c;
        }
    }

    wif.close();
}

【讨论】:

  • 感谢您的反馈。不幸的是 codecvt_utf16 在我的系统上不可用。我没有读取文件的每一行,而是使用 fread() 。它有点麻烦而且不那么整洁,但它确实有效。您的解决方案将是首选解决方案,但正如我所说的那样,这对我来说似乎不可能
  • 您使用的是哪个编译器?您正在使用 auto,这是 C++11 的功能,而 codecvt_utf16 是 C++11 的一部分。您是否在代码中添加了#include &lt;codecvt&gt;
  • 我在 Ubuntu 14.04 上使用 gcc4.9。我无法包含 因为它不可用。我只能访问codecvtcodecvt_basecodecvt_byname
  • 为什么要以二进制方式打开文件?
  • @MarkRansom &lt;codecvt&gt; 中的类在 C++17 中确实已被弃用,但目前还没有标准的替代品。我认为标准委员会正在推动人们使用外部 Unicode 库。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多