Как прочитать файл в кодировке UTF-8, содержащий китайские символы, и правильно вывести их на консоль?

Я пишу веб-сканер для получения некоторых китайских веб-файлов. Выбранные файлы кодируются в utf-8. И мне нужно прочитать этот файл, чтобы выполнить некоторый синтаксический анализ, например, извлечь URL-адреса и китайские символы. Но я обнаружил, что когда я читал файл в переменную std :: string и выводил его в консоль, китайские символы становились символами мусора. Я применил boost :: regex к переменной std :: string и могу извлечь все URL-адреса, кроме китайских символов.

Как я могу решить эти проблемы?

P.S. Мои файлы CPP по умолчанию кодируются как ANSI, операционная система - Win8 на китайском языке;


person Bruce Yang    schedule 25.11.2013    source источник
comment
Похоже, вам нужно изменить «кодовую страницу» с UTF-8 на любую кодовую страницу, которую ваша консоль использует для китайских символов. Вызовите MultiByteToWideChar, чтобы изменить UTF-8 на Unicode, а затем WideCharToMultiByte, чтобы перейти с Unicode на вашу локальную кодовую страницу.   -  person john    schedule 25.11.2013
comment
Скорее всего виновата консоль. Попробуйте > выполнить операцию с файлом. Если окажется, что это действительный UTF-8 с китайскими символами, значит, ваша программа работает нормально, и это вопрос Windows. (Конечно, вам все равно может потребоваться изменить свою программу для работы с Windows, но вы будете знать, кто виноват.)   -  person aib    schedule 25.11.2013
comment
@aib Да, когда я перенаправляю переменную std :: string в другой файл, содержимое по-прежнему является допустимым UTF-8 с символами Chiese. Кодовая страница моей консоли "936(ANSI/OEM - 简体中文 GBK)".   -  person Bruce Yang    schedule 26.11.2013


Ответы (3)


Этот код может помочь (он был скомпилирован с помощью VC ++ 2010). Я тестировал его с файлом UTF-8, содержащим нелатинские символы, и, похоже, он работает, но я не знаю, будет ли он нормально работать с китайскими символами. Для получения дополнительной информации проверьте следующие ссылки: _setmode и codecvt_utf8.

#include <iostream>
#include <fstream>
#include <string>
#include <locale>
#include <codecvt>
#include <fcntl.h>
#include <io.h>

using namespace std;    // Sorry for this!

void read_all_lines(const wchar_t *filename)
{
    wifstream wifs;
    wstring txtline;
    int c = 0;

    wifs.open(filename);
    if(!wifs.is_open())
    {
        wcerr << L"Unable to open file" << endl;
        return;
    }
    // We are going to read an UTF-8 file
    wifs.imbue(locale(wifs.getloc(), new codecvt_utf8<wchar_t, 0x10ffff, consume_header>()));
    while(getline(wifs, txtline))
        wcout << ++c << L'\t' << txtline << L'\n';
    wcout << endl;
}

int _tmain(int argc, _TCHAR* argv[])
{
    // Console output will be UTF-16 characters
    _setmode(_fileno(stdout), _O_U16TEXT);
    if(argc < 2)
    {
        wcerr << L"Filename expected!" << endl;
        return 1;
    }
    read_all_lines(argv[1]);
    return 0;
}

Если китайские символы выглядят не так, как ожидалось, убедитесь, что консоль использует шрифт, поддерживающий UTF-16 (т. Е. Не используйте растровые шрифты).

person Jigsore    schedule 26.11.2013
comment
Ваше решение работало на другой платформе или только в VC под Windows? - person Wael Boutglay; 08.01.2016

В общем, используйте w варианты, (wstring, wfstream, wcout), установите локали в соответствии с требованиями, повесьте L перед строковыми литералами. locale::global(locale("")) настраивается в соответствии со средой по умолчанию, затем для каждого потока, который не выполняется в соответствии с этим значением по умолчанию, например. wcout.imbue(locale("Chinese_China.936")) может быть именем Microsoft для языковых настроек вашего терминала. Этого всегда было достаточно, чтобы делать то, что я хочу, надеюсь, это сработает и для вас.

#include <iostream>
#include <locale>
using namespace std;
int main() {
  locale::global(locale(""));
  wstring word;
  while (wcin >>word)
    wcout<<word<<'\n';
  wcout<<L"好運n";
}
person jthill    schedule 25.11.2013

если вам нужно правильно отображать символы, вы можете использовать libiconv от GNU. если вам нужно только обрабатывать URL-адреса, std :: string отлично работает. проблема заключается в кодовой странице консоли Windows, а не в самой строке. использование локали зависит от реализации ОС и stdc ++ lib, поэтому я не рекомендую использовать.

Window MultiByteToWideChar может помочь, но вам нужно проверить спецификации MS о том, как функции выполняют преобразование строк.

person wacky6    schedule 25.11.2013