Чтение файла UTF-16 в c ++ - PullRequest
0 голосов
/ 05 июня 2018

Я пытаюсь прочитать файл с кодировкой 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;
}

Файл может содержать латиницу и кириллицу.Я создал файл со строкой «Тест-тест».И этот код возвращает мне

/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 (теги / RELEASE_380 / final)
  • версия clang 5.0.0-3 ~ 16.04.1 (теги / RELEASE_500/ окончательно)

Ответы [ 2 ]

0 голосов
/ 08 июня 2018

Замените на это - 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;
  } 
0 голосов
/ 06 июня 2018

В идеале вы должны сохранять файлы в 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);
...