使用 std::wifstream 读取带有特殊字符的 unicode 文件

Posted

技术标签:

【中文标题】使用 std::wifstream 读取带有特殊字符的 unicode 文件【英文标题】:Read unicode file with special characters using std::wifstream 【发布时间】:2014-09-30 13:12:27 【问题描述】:

在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 显示了一个示例。 【参考方案1】:

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

#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 库。

以上是关于使用 std::wifstream 读取带有特殊字符的 unicode 文件的主要内容,如果未能解决你的问题,请参考以下文章

在 Apache Web 服务器中读取带有特殊字符的图像

如何在python中读取带有特殊字符的文本文件

读取带有特殊字符的字符串并在`tr`和`sed`中使用它[关闭]

显示带有问号的菱形等特殊字符的网站

php文件字​​符编码、mysql数据库字符编码、特殊字符

2词法分析--4字面值--1字符串和字节串