2015-02-24 1 views
2

J'ai un simple morceau de code qui ouvre un flux de fichiers & imprime des choses. Dès qu'il frappe un caractère Unicode, il arrête de lire.caractères Unicode ne pas lire - C++

Mon système est réglé sur paramètres régionaux japonais & Visual Studio est réglé pour compiler en unicode. Pas sûr de ce qui se passe.

fichier:

<abc \ 单位孤>hajslklfasjflkesjfleajflj 

Fichier 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 

Code de la pièce:

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(); 

Sortie:

Output

+0

http://www.cplusplus.com/reference/ios/ios/good/ pourquoi ne pas savoir exactement pourquoi votre flux n'est plus bon. – thang

+0

Etes-vous sûr que le fichier est codé en UTF8? –

+0

Pouvez-vous faire un vidage hexadécimal du fichier? –

Répondre

2

Il est bien lu, il est tout simplement pas écrire.

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

Malheureusement std::wcout ne fiable pas réellement obtenir Unicode à un terminal.

Bien que le terminal Windows fonctionne de manière native dans les unités de code UTF-16, std::wcout est toujours défini dans des termes purement octets. Il convertit sa grande entrée vers octets en utilisant l'encodage par défaut des paramètres régionaux avant d'écrire le bon vieux flux stdout octets Unicode ignorant (qui pourrait être une redirection de fichier natif-octets ainsi qu'une borne de sortie en mode natif Unicode, après tout) .

Donc, std::wcout finit par être tout aussi limité sous Windows que toutes les autres interfaces IO octets, restreintes aux caractères de la page de codes actuelle. Votre page de codes est probablement 932, où le caractère U + 5355 n'existe pas, alors essayer de l'écrire casse le flux.

La définition de la page de codes actuelle sur 65001 dans le but d'obtenir la même sortie UTF-8 que toutes les autres plates-formes modernes préfèrent ne fonctionne pas correctement en raison de bogues multi-octets. MS a laissé cela cassé pour beaucoup de versions multiples alors attendez-vous à ce que l'UTF-8 reste un citoyen de seconde classe sous Windows.

Quelques alternatives:

  1. utiliser l'API Win32 WriteConsoleW au lieu d'interfaces stdlib. (Nécessite soin de gérer la redirection de sortie possible, et si vous avez besoin que votre projet soit multiplateforme compatible.)

  2. Utilisez _setmode avec _O_U16TEXT pour changer le flux de sortie en octets UTF-16 codés. Voir l'exemple au this question. Il semble que toutes les interfaces ne fonctionnent pas nécessairement dans ce mode; vous avez probablement des problèmes si vous essayez d'utiliser les interfaces d'octets en même temps.

  3. Sortie explicitement des octets codés en UTF-8 et nécessite que les utilisateurs de la console Windows supportent simplement le mojibake et les glyphes manquants qui en résultent.

Il est dommage que cette histoire soit encore si misérable.

+0

Merci, bon à savoir à ce sujet. – RandomClown

0

std :: wcout peut y être associé.

Essayez cette page: 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"); 

selon la façon dont vous entrez dans le chcp intvalue commande, vous obtiendrez une sortie directement liée à codepage 1252 et 65001

J'ai écrit une test pour Unicode une semaine ou deux à l'époque. Il pourrait vous aider, veuillez voir https://github.com/MagnusTiberius/wcutil/blob/master/widechartest.cpp pour plus de détails.

Vous pouvez également vérifier ceci sur la façon de définir la page de code pour rendre double/multi-byte.

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