2015-02-24 4 views
2

У меня есть простой фрагмент кода, который открывает поток файлов. & печатает материал. Как только он попадает в символ юникода, он перестает читать.Unicode Character Not Reading - C++

Моя система настроена на японский язык & Visual Studio настроен на компиляцию как unicode. Не уверен, что происходит.

Файл:

<abc \ 单位孤>hajslklfasjflkesjfleajflj 

Файл Hex Dump:

EF BB BF 3C 61 62 63 20 5C 20 E5 8D 95 E4 BD 8D 
E5 AD A4 3E 68 61 6A 73 6C 6B 6C 66 61 73 6A 66 
6C 6B 65 73 6A 66 6C 65 61 6A 66 6C 6A 0D 0A 

Код детали:

std::wifstream fin(path, std::ios::binary); 
fin.imbue(std::locale(fin.getloc(), new std::codecvt_utf8_utf16<wchar_t, 0x10ffff, std::consume_header>)); 
if (!fin.good()) return; 

while (fin.good()) { 
    std::wcout << (wchar_t)fin.get() << "\n"; 
} 

fin.close(); 

Выход:

Output

+0

http://www.cplusplus.com/reference/ios/ios/good/ почему бы вам не понять, почему именно ваш поток не уедешь. – thang

+0

Вы уверены, что файл UTF8 закодирован? –

+0

Можете ли вы сделать шестнадцатеричный дамп файла? –

ответ

2

Это нормально читать, это просто не писать.

std::wcout << (wchar_t)fin.get() << "\n"; 

К сожалению std::wcout фактически не надежно получить Unicode к терминалу.

Хотя терминал Windows работает из кодированных блоков UTF-16, std::wcout по-прежнему определяется исключительно на основе байтов. Он преобразует свой широкий вход вниз в байты, используя стандартную кодировку по умолчанию для локали, прежде чем записывать в старый добрый поток untele unteode byte stdout (который, в конце концов, может быть перенаправлением файла изначально байтов, а также вывода изначально-Unicode) ,

Таким образом, std::wcout заканчивается как ограниченный под Windows, так и все остальные байтовые интерфейсы ввода-вывода, ограниченные символами на текущей кодовой странице. Ваша кодовая страница, вероятно, 932, где символ U + 5355 не существует, поэтому попытка написать его разбивает поток.

Установка текущей кодовой страницы на 65001 в попытке получить тот же выход UTF-8, который предпочитают все другие современные платформы, не совсем работает из-за множества многобайтовых ошибок подсчета символов в базовой среде C. MS оставили это сломанным для многих нескольких версий, поэтому ожидайте, что UTF-8 останется гражданином второго сорта под Windows.

Некоторые альтернативы:

  1. Использование в Win32 API WriteConsoleW вместо STDLIB интерфейсов. (Требуется осторожность, чтобы справиться с возможным перенаправление вывода, и если вам нужен проект для кросс-платформенной совместимости.)

  2. _setmode Использование с _O_U16TEXT, чтобы изменить выходной поток в UTF-16 закодированных байт. См. Пример в this question. Кажется, не все интерфейсы обязательно работают в этом режиме; у вас наверняка возникнут проблемы, если вы попытаетесь одновременно использовать байтовые интерфейсы.

  3. Вывести явно UTF-8-кодированные байты и потребовать, чтобы пользователи консоли Windows просто мирились с моджибаке и отсутствующими глифами.

Жаль, что эта история по-прежнему так несчастна.

+0

Спасибо, приятно знать об этом. – RandomClown

0

std :: wcout, возможно, имеет к этому какое-то отношение.

Попробуйте эту страницу: https://alfps.wordpress.com/2011/12/08/unicode-part-2-utf-8-stream-mode/

//std::locale loc2 = std::locale("zh-CN"); 
//SetConsoleOutputCP(CP_UTF8); 
//SetConsoleCP(65001); 
_setmode(_fileno(stdout), _O_U16TEXT); 
std::wcout << "text:" << L"<abc单位孤>hajslklfasjflkesjfleajflj" << "\n"; 
_setmode(_fileno(stdout), _O_WTEXT); 
std::wcout << "text:" << L"<abc单位孤>hajslklfasjflkesjfleajflj" << "\n"; 
_setmode(_fileno(stdout), _O_U8TEXT); 
std::wcout << "text:" << L"<abc单位孤>hajslklfasjflkesjfleajflj" << "\n"; 
//setlocale(LC_ALL, "C"); 
//fputs("hello 2: ΓΔΕΘΛΞΠΣΦΨЪЩШЫЮЯ\n", stdout); 
std::wcout << "text:" << L"hello 2: ΓΔΕΘΛΞΠΣΦΨЪЩШЫЮЯ" << "\n"; 
wprintf(L">>> hello 2: ΓΔΕΘΛΞΠΣΦΨЪЩШЫЮЯ \n"); 
std::locale loc3 = std::locale("en-US"); 
_setmode(_fileno(stdout), _O_U16TEXT); 
std::wcout << "text:" << L"<abc单位孤>hajslklfasjflkesjfleajflj" << "\n"; 
_setmode(_fileno(stdout), _O_WTEXT); 
std::wcout << "text:" << L"<abc单位孤>hajslklfasjflkesjfleajflj" << "\n"; 
_setmode(_fileno(stdout), _O_U8TEXT); 
std::wcout << "text:" << L"<abc单位孤>hajslklfasjflkesjfleajflj" << "\n"; 
//setlocale(LC_ALL, "C"); 
//fputs("hello 2: ΓΔΕΘΛΞΠΣΦΨЪЩШЫЮЯ\n", stdout); 
std::wcout << "text:" << L"hello 2: ΓΔΕΘΛΞΠΣΦΨЪЩШЫЮЯ" << "\n"; 
wprintf(L">>> hello 2: ΓΔΕΘΛΞΠΣΦΨЪЩШЫЮЯ \n"); 

в зависимости от того, как вы входите в CHCP intvalue команды, вы получите выход непосредственно связанный с кодовой страницей 1252 и 65001

Я действительно писал тест для unicode через неделю или две. Это может помочь вам, см. https://github.com/MagnusTiberius/wcutil/blob/master/widechartest.cpp.

Вы также можете проверить это, как установить кодовую страницу для визуализации двойного/многобайтового.

http://www.curlybrace.com/words/2014/10/03/windows-console-and-doublemulti-byte-character-set/