【问题标题】:Reading UTF-16 file in c++在 C++ 中读取 UTF-16 文件
【发布时间】:2018-06-05 09:37:10
【问题描述】:

我正在尝试使用 BOM 读取具有 UTF-16LE 编码的文件。 我试过这段代码

#include <iostream>
#include <fstream>
#include <locale>
#include <codecvt>

int main() {

  std::wifstream fin("/home/asutp/test");
  fin.imbue(std::locale(fin.getloc(), new std::codecvt_utf16<wchar_t, 0x10ffff, std::consume_header>));
  if (!fin) {
    std::cout << "!fin" << std::endl;
    return 1;
  }
  if (fin.eof()) {
    std::cout << "fin.eof()" << std::endl;
    return 1;
  }
  std::wstring wstr;
  getline(fin, wstr);
  std::wcout << wstr << std::endl;

  if (wstr.find(L"Test") != std::string::npos) {
    std::cout << "Found" << std::endl;
  } else {
    std::cout << "Not found" << std::endl;
  }

  return 0;
}

文件可以包含拉丁文和西里尔文。我用字符串“Test тест”创建了文件。这段代码返回了我

/home/asutp/CLionProjects/untitled/cmake-build-debug/untitled

Not found

Process finished with exit code 0

我使用的是 Linux Mint 18.3 x64、Clion 2018.1

试过

  • gcc 版本 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.9)
  • clang 版本 3.8.0-2ubuntu4 (tags/RELEASE_380/final)
  • clang 版本 5.0.0-3~16.04.1 (tags/RELEASE_500/final)

【问题讨论】:

  • 我的测试文件rgho.st/7xH6WMcGZ
  • 打印出wstr中的内容?
  • @PaulSanders 有 std::wcout
  • 抱歉,错过了。我不是std::codecvt 方面的专家,但您可以考虑切换到std::basic_string&lt;char16_t&gt; 和代码u"Test" 而不是L"Test",从而完全不需要它。
  • 这段代码对我来说很好用。你确定你的文件有BOM吗?

标签: c++ utf-16


【解决方案1】:

理想情况下,您应该以 UTF8 保存文件,因为 Window 具有更好的 UTF8 支持(除了在控制台窗口中显示 Unicode),而 POSIX 对 UTF16 的支持有限。甚至 Microsoft 产品也支持 UTF8 在 Windows 中保存文件。

作为替代方案,您可以将 UTF16 文件读入缓冲区并将其转换为 UTF8

std::ifstream fin("utf16.txt", std::ios::binary);
fin.seekg(0, ios::end);
size_t size = (size_t)fin.tellg();

//skip BOM
fin.seekg(2, ios::beg);
size -= 2;

std::u16string u16((size / 2) + 1, '\0');
fin.read((char*)&u16[0], size);

std::string utf8 = std::wstring_convert<
    std::codecvt_utf8_utf16<char16_t>, char16_t>{}.to_bytes(u16);


要么
std::ifstream fin("utf16.txt", std::ios::binary);

//skip BOM
fin.seekg(2);

//read as raw bytes
std::stringstream ss;
ss << fin.rdbuf();
std::string bytes = ss.str();

//make sure len is divisible by 2
int len = bytes.size();
if(len % 2) len--;

std::wstring sw;
for(size_t i = 0; i < len;)
{
    //little-endian
    int lo = bytes[i++] & 0xFF;
    int hi = bytes[i++] & 0xFF;
    sw.push_back(hi << 8 | lo);
}

std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> convert;
std::string utf8 = convert.to_bytes(sw);

【讨论】:

  • 我正在获取 UTF-16 编码的新文件,但我无法更改它们。我已经使用wstring_convert 得到了类似的解决方案。但无论如何,非常感谢您的解决方案,很高兴了解不同的方法。但是,我仍然想知道,为什么 imbue 方法对我不起作用,因为其他人很难过它有效,即使在 linux 上也是如此
  • 这个答案没有考虑代理对。
  • @BarmakShemirani 抱歉,我以为您正在尝试将代理对的一部分转换为 utf8,但我错了,我刚刚尝试了您的代码,发现它有效。对于误导性评论和反对票,我深表歉意,但除非帖子被编辑,否则我无法撤消反对票。下次我会更加谨慎。
  • @Searene 我很欣赏你的评论。这比不解释原因就投反对票的人要好。顺便说一句,我编辑了答案。
【解决方案2】:

用这个替换 - std::wstring::npos(不是std::string::npos) - 并且你的代码必须工作:

...
 //std::wcout << wstr << std::endl;

  if (wstr.find(L"Test") == std::wstring::npos) {
    std::cout << "Not Found" << std::endl;
  } else {
    std::cout << "found" << std::endl;
  } 

【讨论】:

  • 没有帮助。问题不在于搜索,而在于读取文件
  • @Kot Shrodingera - 它适用于 Ubuntu 16.04、x64 和 Windows 7。消息“未找到”是因为您的搜索代码错误。
  • 它在我的系统上不起作用,我不知道为什么。问题不在于搜索代码,getline 后 wstr 为空
  • @Kot Shrodingera - 然后,它正在从问题所在的文件中读取。来自 wsstd::wstring 的 getline 工作正常。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-09-12
  • 1970-01-01
  • 1970-01-01
  • 2012-08-20
  • 2021-07-01
  • 2017-02-12
  • 1970-01-01
相关资源
最近更新 更多