Sortie de chaînes Unicode dans l’application de console Windows

Salut, j’essayais de sortir une chaîne Unicode vers une console avec iostreams et a échoué.

J’ai trouvé ceci: Utiliser la police unicode dans l’application de console c ++ et cet extrait fonctionne.

SetConsoleOutputCP(CP_UTF8); wchar_t s[] = L"èéøÞǽлљΣæča"; int bufferSize = WideCharToMultiByte(CP_UTF8, 0, s, -1, NULL, 0, NULL, NULL); char* m = new char[bufferSize]; WideCharToMultiByte(CP_UTF8, 0, s, -1, m, bufferSize, NULL, NULL); wprintf(L"%S", m); 

Cependant, je n’ai trouvé aucun moyen de générer unicode correctement avec iostreams. Aucune suggestion?

Cela ne fonctionne pas:

 SetConsoleOutputCP(CP_UTF8); utf8_locale = locale(old_locale,new boost::program_options::detail::utf8_codecvt_facet()); wcout.imbue(utf8_locale); wcout << L"¡Hola!" << endl; 

EDIT Je n’ai pas trouvé d’autre solution que d’envelopper cet extrait dans un stream. J’espère que quelqu’un a de meilleures idées.

 //Unicode output for a Windows console ostream &operator-(ostream &stream, const wchar_t *s) { int bufSize = WideCharToMultiByte(CP_UTF8, 0, s, -1, NULL, 0, NULL, NULL); char *buf = new char[bufSize]; WideCharToMultiByte(CP_UTF8, 0, s, -1, buf, bufSize, NULL, NULL); wprintf(L"%S", buf); delete[] buf; return stream; } ostream &operator-(ostream &stream, const wssortingng &s) { stream - s.c_str(); return stream; } 

J’ai vérifié une solution ici en utilisant Visual Studio 2010. Via cet article MSDN et l’ article de blog MSDN . L’astuce est un appel obscur à _setmode(..., _O_U16TEXT) .

Solution:

 #include  #include  #include  int wmain(int argc, wchar_t* argv[]) { _setmode(_fileno(stdout), _O_U16TEXT); std::wcout << L"Testing unicode -- English -- Ελληνικά -- Español." << std::endl; } 

Capture d'écran:

Unicode dans la console

Le paramètre wcout doit avoir des parameters régionaux différents de ceux du CRT. Voici comment cela peut être corrigé:

 int _tmain(int argc, _TCHAR* argv[]) { char* locale = setlocale(LC_ALL, "English"); // Get the CRT's current locale. std::locale lollocale(locale); setlocale(LC_ALL, locale); // Restore the CRT. std::wcout.imbue(lollocale); // Now set the std::wcout to have the locale that we got from the CRT. std::wcout << L"¡Hola!"; std::cin.get(); return 0; } 

Je viens de le tester et il affiche la chaîne absolument parfaite.

SetConsoleCP () et chcp ne font pas la même chose!

Prenez cet extrait de programme:

 SetConsoleCP(65001) // 65001 = UTF-8 static const char s[]="tränenüberströmt™\n"; DWORD slen=lstrlen(s); WriteConsoleA(GetStdHandle(STD_OUTPUT_HANDLE),s,slen,&slen,NULL); 

Le code source doit être enregistré au format UTF-8 sans nomenclature (marque d’ordre des octets; signature). Ensuite, le compilateur Microsoft cl.exe prend les chaînes UTF-8 telles quelles .
Si ce code est enregistré avec la nomenclature, cl.exe convertit la chaîne en ANSI (c.-à-d. CP1252), ce qui ne correspond pas à CP65001 (= UTF-8).

Changez la police d’ affichage en console Lucidia , sinon, la sortie UTF-8 ne fonctionnera pas du tout.

  • Type: chcp
  • Réponse: 850
  • Type: test.exe
  • Réponse: tr├ñnen├╝berstr├ÂmtÔäó
  • Type: chcp
  • Réponse: 65001 – Ce paramètre a été modifié par SetConsoleCP() mais sans effet utile.
  • Type: chcp 65001
  • Type: test.exe
  • Réponse: tränenüberströmt™ – Tout va bien maintenant.

Testé avec: Windows XP SP3 allemand

Unicode Hello World en chinois

Voici un Hello World en chinois. En fait, c’est juste “Bonjour”. Je l’ai testé sur Windows 10, mais je pense que cela pourrait fonctionner depuis Windows Vista. Avant Windows Vista, ce sera difficile, si vous voulez une solution programmatique, au lieu de configurer la console / le registre, etc. Jetez-y un œil si vous avez vraiment besoin de le faire sous Windows 7:

Je ne veux pas prétendre que c’est la seule solution, mais c’est ce qui a fonctionné pour moi.

Contour

  1. Configuration du projet Unicode
  2. Définir la page de code de la console sur unicode
  3. Recherchez et utilisez une police prenant en charge les caractères à afficher
  4. Utilisez les parameters régionaux de la langue que vous souhaitez afficher
  5. Utilisez la sortie de caractères large std::wcout

1 configuration du projet

J’utilise Visual Studio 2017 CE. J’ai créé une application de console vierge. Les parameters par défaut sont corrects. Mais si vous rencontrez des problèmes ou si vous utilisez une autre idée, vous pouvez vérifier les points suivants:

Dans vos propriétés de projet, recherchez les propriétés de configuration -> Général -> Valeurs par défaut du projet -> Jeu de caractères. Il doit s’agir de “Utiliser le jeu de caractères Unicode” et non “Multi-Byte”. Cela définira les macros de préprocesseur _UNICODE et UNICODE pour vous.

 int wmain(int argc, wchar_t* argv[]) 

Je pense aussi que nous devrions utiliser la fonction wmain au lieu de la fonction main . Ils fonctionnent tous les deux, mais dans un environnement unicode, wmain peut être plus pratique.

Mes fichiers source sont également encodés en UTF-16-LE, ce qui semble être la valeur par défaut dans Visual Studio 2017.

2. page de code de la console

C’est assez évident. Nous avons besoin de la page de code unicode dans la console. Si vous voulez vérifier votre page de code par défaut, ouvrez simplement une console et tapez chcp sans aucun argument. Nous devons le changer pour 65001, qui est la page de code UTF-8. Windows Codepage Identifiers Il existe une macro de préprocesseur pour cette page de code: CP_UTF8 . Je devais définir à la fois la page de code d’entrée et de sortie. Lorsque j’ai omis l’un ou l’autre, la sortie était incorrecte.

 SetConsoleOutputCP(CP_UTF8); SetConsoleCP(CP_UTF8); 

Vous pourriez également vouloir vérifier les valeurs de retour booléennes de ces fonctions.

3. Choisissez une police

Jusqu’à présent, je n’ai pas trouvé de police de console prenant en charge tous les personnages. J’ai donc dû en choisir un. Si vous voulez sortir des caractères qui ne sont que partiellement disponibles dans une police et dans une autre, alors je pense qu’il est impossible de trouver une solution. Seulement peut-être s’il existe une police qui supporte tous les caractères. Mais je n’ai pas non plus cherché à installer une police.

Je pense qu’il n’est pas possible d’utiliser deux fonts différentes dans la même fenêtre de la console en même temps.

Comment trouver une police compatible? Ouvrez votre console, accédez aux propriétés de la fenêtre de la console en cliquant sur l’icône en haut à gauche de la fenêtre. Allez dans l’onglet des fonts et choisissez une police et cliquez sur OK. Ensuite, essayez d’entrer vos caractères dans la fenêtre de la console. Répétez cette opération jusqu’à ce que vous trouviez une police avec laquelle vous pouvez travailler. Notez ensuite le nom de la police.

Vous pouvez également modifier la taille de la police dans la fenêtre des propriétés. Si vous avez trouvé une taille qui vous convient, notez les valeurs de taille affichées dans la fenêtre des propriétés dans la section “police sélectionnée”. Il affichera la largeur et la hauteur en pixels.

Pour définir réellement la police par programmation, vous utilisez:

 CONSOLE_FONT_INFOEX fontInfo; // ... configure fontInfo SetCurrentConsoleFontEx(hConsole, false, &fontInfo); 

Voir mon exemple à la fin de cette réponse pour plus de détails. Ou recherchez-le dans le manuel: SetCurrentConsoleFont . Cette fonction existe uniquement depuis Windows Vista.

4. Définissez les parameters régionaux

Vous devrez définir les parameters régionaux pour les parameters régionaux de la langue des caractères à imprimer.

 char* a = setlocale(LC_ALL, "chinese"); 

La valeur de retour est intéressante. Il contiendra une chaîne pour décrire exactement la localisation choisie. Juste essayer 🙂 J’ai testé avec le chinese et l’ german . Plus d’infos: setlocale

5. Utilisez une sortie de caractères large

Pas grand chose à dire ici. Si vous voulez sortir des caractères larges, utilisez ceci par exemple:

 std::wcout << L"你好" << std::endl; 

Oh, et n'oubliez pas le préfixe L pour les caractères larges! Et si vous tapez des caractères Unicode littéraux comme celui-ci dans le fichier source, le fichier source doit être codé en Unicode. Comme par défaut, Visual Studio utilise UTF-16-LE. Ou peut-être utiliser notepad ++ et définir l'encodage sur UCS-2 LE BOM .

Exemple

Enfin, je mets tout cela en exemple:

 #include  #include  #include  #include  #include  #include  int wmain(int argc, wchar_t* argv[]) { SetConsoleTitle(L"My Console Window - 你好"); HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); char* a = setlocale(LC_ALL, "chinese"); SetConsoleOutputCP(CP_UTF8); SetConsoleCP(CP_UTF8); CONSOLE_FONT_INFOEX fontInfo; fontInfo.cbSize = sizeof(fontInfo); fontInfo.FontFamily = 54; fontInfo.FontWeight = 400; fontInfo.nFont = 0; const wchar_t myFont[] = L"KaiTi"; fontInfo.dwFontSize = { 18, 41 }; std::copy(myFont, myFont + (sizeof(myFont) / sizeof(wchar_t)), fontInfo.FaceName); SetCurrentConsoleFontEx(hConsole, false, &fontInfo); std::wcout << L"Hello World!" << std::endl; std::wcout << L"你好!" << std::endl; return 0; } 

À votre santé !

Je ne pense pas qu’il y ait une réponse facile. En regardant les pages de code de console et la fonction SetConsoleCP, il semble que vous deviez configurer une page de code appropriée pour le jeu de caractères que vous allez sortir.

Récemment, je voulais diffuser unicode de Python vers la console Windows et voici le minimum nécessaire:

  • Vous devez définir la police de la console sur celle couvrant les symboles Unicode. Il n’y a pas beaucoup de choix: Propriétés de la console> Police> Console Lucida
  • Vous devez changer la page de code de la console actuelle: exécutez chcp 65001 dans la console ou utilisez la méthode correspondante dans le code C ++
  • écrire sur la console en utilisant WriteConsoleW

Regardez dans un article intéressant sur java unicode sur la console Windows

De plus, en Python, vous ne pouvez pas écrire dans sys.stdout par défaut dans ce cas, vous devrez le remplacer par quelque chose en utilisant os.write (1, binaryssortingng) ou appeler directement un wrapper autour de WriteConsoleW. Semble en C ++, vous devrez faire la même chose.

Tout d’abord, désolé, je n’ai probablement pas les fonts nécessaires, donc je ne peux pas encore le tester.

Quelque chose a l’air un peu louche ici

 // the following is said to be working SetConsoleOutputCP(CP_UTF8); // output is in UTF8 wchar_t s[] = L"èéøÞǽлљΣæča"; int bufferSize = WideCharToMultiByte(CP_UTF8, 0, s, -1, NULL, 0, NULL, NULL); char* m = new char[bufferSize]; WideCharToMultiByte(CP_UTF8, 0, s, -1, m, bufferSize, NULL, NULL); wprintf(L"%S", m); // <-- upper case %S in wprintf() is used for MultiByte/utf-8 // lower case %s in wprintf() is used for WideChar printf("%s", m); // <-- does this work as well? try it to verify my assumption 

tandis que

 // the following is said to have problem SetConsoleOutputCP(CP_UTF8); utf8_locale = locale(old_locale, new boost::program_options::detail::utf8_codecvt_facet()); wcout.imbue(utf8_locale); wcout << L"¡Hola!" << endl; // <-- you are passing wide char. // have you tried passing the multibyte equivalent by converting to utf8 first? int bufferSize = WideCharToMultiByte(CP_UTF8, 0, s, -1, NULL, 0, NULL, NULL); char* m = new char[bufferSize]; WideCharToMultiByte(CP_UTF8, 0, s, -1, m, bufferSize, NULL, NULL); cout << m << endl; 

qu'en est-il de

 // without setting locale to UTF8, you pass WideChars wcout << L"¡Hola!" << endl; // set locale to UTF8 and use cout SetConsoleOutputCP(CP_UTF8); cout << utf8_encoded_by_converting_using_WideCharToMultiByte << endl; 

Il y a quelques problèmes avec les stream mswcrt et io.

  1. Astuce _setmode (_fileno (stdout), _O_U16TEXT); travailler uniquement pour MS VC ++ pas MinGW-GCC. De plus, il arrive parfois que des accidents se produisent en fonction de la configuration de Windows.
  2. SetConsoleCP (65001) pour UTF-8. Peut échouer dans de nombreux scénarios de caractères multi-octets, mais est toujours OK pour UTF-16LE
  3. Vous devez restaurer la page de code de la prévisualisation à la sortie de l’application.

La console Windows prend en charge UNICODE avec les fonctions ReadConsole et WriteConsole en mode UTF-16LE. Effet d’arrière-plan – la tuyauterie dans ce cas ne fonctionnera pas. C’est à dire myapp.exe >> ret.log apporte à 0 octet le fichier ret.log. Si vous êtes d’accord avec ce fait, vous pouvez essayer ma bibliothèque comme suit.

 const char* umessage = "Hello!\nПривет!\nПривіт!\nΧαιρετίσματα!\nHelló!\nHallå!\n"; ... #include  #include  ... std::ostream& cout = io::console::out_stream(); cout << umessage << 1234567890ull << '\n' << 123456.78e+09 << '\n' << 12356.789e+10L << '\n' << std::hex << 0xCAFEBABE << std::endl; 

Library convertit automatiquement votre UTF-8 en UTF-16LE et l'écrit dans la console à l'aide de WriteConsole. Il y a aussi des erreurs et des stream d'entrée. Un autre avantage de la bibliothèque - les couleurs.

Lien sur un exemple d'application: https://github.com/incoder1/IO/tree/master/examples/iostreams

La page d'accueil de la bibliothèque: https://github.com/incoder1/IO

Capture d'écran:

J’ai eu un problème similaire, Output Unicode à la console Utilisation de C ++, dans Windows contient le bijou que vous devez faire chcp 65001 dans la console avant d’exécuter votre programme.

Il y a peut-être un moyen de le faire par programmation, mais je ne sais pas ce que c’est.

Affichage correct des caractères d’Europe occidentale dans la console Windows

Longue histoire courte:

  1. utilisez chcp pour trouver quelle page de code fonctionne pour vous. Dans mon cas, c’était chcp 28591 pour l’Europe occidentale.
  2. éventuellement, le rendre par défaut: REG ADD HKCU\Console /v CodePage /t REG_DWORD /d 28591

Histoire de la découverte

J’ai eu un problème similaire avec Java. C’est juste cosmétique, car il implique des lignes de log envoyées à la console; mais c’est toujours agaçant.

La sortie de notre application Java est supposée être en UTF-8 et s’affiche correctement dans la console d’eclipse. Mais dans la console Windows, il ne montre que les caractères de dessin des boîtes ASCII: Inicializaci├│n et art├¡culos au lieu de Inicialización et artículos .

Je suis tombé sur une question connexe et j’ai mélangé certaines des réponses pour arriver à la solution qui fonctionnait pour moi. La solution consiste à modifier la page de codes utilisée par la console et à utiliser une police prenant en charge UNICODE (comme les consolas ou la lucida console ). La police que vous pouvez sélectionner dans le menu système du cosole Windows:

  1. Démarrer une console par l’un des
    • Win + R puis tapez cmd et appuyez sur la touche Return .
    • Appuyez sur la touche Win et tapez cmd suivi de la touche return .
  2. Ouvrez le menu système par l’un des
    • cliquez sur l’icône du coin supérieur gauche
    • Appuyez sur la Alt + Space
  3. puis sélectionnez “Default” pour modifier le comportement de toutes les fenêtres de console suivantes
  4. cliquez sur l’onglet “Police”
  5. Sélectionnez Consolas ou Lucida console
  6. Cliquez sur OK

En ce qui concerne la page de code, pour un cas unique, vous pouvez le faire avec la commande chcp et ensuite vous devez déterminer quelle page de code est correcte pour votre jeu de caractères. Plusieurs réponses ont suggéré la page de code UTF-8, qui est 65001, mais cette page de codes n’a pas fonctionné pour mes caractères espagnols.

Une autre réponse a suggéré un script batch pour sélectionner de manière interactive la page de codes souhaitée dans une liste. Là, j’ai trouvé la page de code pour ISO-8859-1 dont j’avais besoin: 28591. Vous pouviez donc exécuter

 chcp 28591 

avant chaque exécution de votre application. Vous pouvez vérifier quelle page de code vous convient le mieux dans la page Identificateurs de page de code MSDN .

Une autre réponse indiquait comment conserver la page de codes sélectionnée par défaut pour votre console Windows. Cela implique de modifier le registre. Considérez donc que vous pouvez bricoler votre ordinateur en utilisant cette solution.

 REG ADD HKCU\Console /v CodePage /t REG_DWORD /d 28591 

Cela crée la valeur CodePage avec les données 28591 dans la clé de registre HKCU \ Console. Et cela a fonctionné pour moi.

Veuillez noter que HKCU (“HKEY_CURRENT_USER”) est uniquement pour l’utilisateur actuel. Si vous voulez le changer pour tous les utilisateurs de cet ordinateur, vous devrez utiliser l’utilitaire regedit et trouver / créer la clé de la Console correspondante (vous devrez probablement créer une clé de Console dans HKEY_USERS\.DEFAULT )