Oui, c'est frustrant - parfois type
et d'autres programmes impriment du charabia, et parfois ils ne le font pas.
Tout d'abord, les caractères Unicode ne s'afficheront que si la police de console actuelle contient les caractères . Utilisez donc une police TrueType comme Lucida Console au lieu de la police raster par défaut.
Mais si la police de la console ne contient pas le caractère que vous essayez d'afficher, vous verrez des points d'interrogation au lieu de charabia. Lorsque vous obtenez du charabia, il se passe plus que de simples paramètres de police.
Lorsque les programmes utilisent des fonctions d'E / S de bibliothèque C standard comme printf
, le codage de sortie du programme doit correspondre au codage de sortie de la console, sinon vous obtiendrez du charabia. chcp
affiche et définit la page de codes actuelle. Toutes les sorties utilisant des fonctions d'E / S de bibliothèque C standard sont traitées comme si elles se trouvaient dans la page de codes affichée par chcp
.
Faire correspondre l'encodage de sortie du programme avec l'encodage de sortie de la console peut être accompli de deux manières différentes:
Un programme peut obtenir la page de codes actuelle de la console en utilisant chcp
ou
GetConsoleOutputCP
, et se configurer pour sortir dans cet encodage, ou
Vous ou un programme pouvez définir la page de codes actuelle de la console en utilisant chcp
ou
SetConsoleOutputCP
pour faire correspondre l'encodage de sortie par défaut du programme.
Cependant, les programmes qui utilisent les API Win32 peuvent écrire des chaînes UTF-16LE directement sur la console avec
WriteConsoleW
. C'est le seul moyen d'obtenir une sortie correcte sans définir de pages de code. Et même lorsque vous utilisez cette fonction, si une chaîne n'est pas dans le codage UTF-16LE pour commencer, un programme Win32 doit passer la page de code correcte à
MultiByteToWideChar
. En outre, WriteConsoleW
ne fonctionnera pas si la sortie du programme est redirigée; plus de violon est nécessaire dans ce cas.
type
fonctionne une partie du temps car il vérifie le début de chaque fichier pour une marque d'ordre d'octets (BOM) UTF-16LE , c'est-à-dire les octets 0xFF 0xFE
. S'il trouve une telle marque, il affiche les caractères Unicode dans le fichier en utilisant WriteConsoleW
indépendamment de la page de code actuelle. Mais pour type
tout fichier sans nomenclature UTF-16LE, ou pour utiliser des caractères non ASCII avec une commande qui n'appelle pas, WriteConsoleW
vous devrez définir la page de code de la console et le codage de sortie du programme pour qu'ils correspondent.
Comment le découvrir?
Voici un fichier de test contenant des caractères Unicode:
ASCII abcde xyz
German äöü ÄÖÜ ß
Polish ąęźżńł
Russian абвгдеж эюя
CJK 你好
Voici un programme Java pour imprimer le fichier de test dans un tas de codages Unicode différents. Il pourrait être dans n'importe quel langage de programmation; il imprime uniquement des caractères ASCII ou des octets codés vers stdout
.
import java.io.*;
public class Foo {
private static final String BOM = "\ufeff";
private static final String TEST_STRING
= "ASCII abcde xyz\n"
+ "German äöü ÄÖÜ ß\n"
+ "Polish ąęźżńł\n"
+ "Russian абвгдеж эюя\n"
+ "CJK 你好\n";
public static void main(String[] args)
throws Exception
{
String[] encodings = new String[] {
"UTF-8", "UTF-16LE", "UTF-16BE", "UTF-32LE", "UTF-32BE" };
for (String encoding: encodings) {
System.out.println("== " + encoding);
for (boolean writeBom: new Boolean[] {false, true}) {
System.out.println(writeBom ? "= bom" : "= no bom");
String output = (writeBom ? BOM : "") + TEST_STRING;
byte[] bytes = output.getBytes(encoding);
System.out.write(bytes);
FileOutputStream out = new FileOutputStream("uc-test-"
+ encoding + (writeBom ? "-bom.txt" : "-nobom.txt"));
out.write(bytes);
out.close();
}
}
}
}
La sortie dans la page de codes par défaut? Déchets totaux!
Z:\andrew\projects\sx\1259084>chcp
Active code page: 850
Z:\andrew\projects\sx\1259084>java Foo
== UTF-8
= no bom
ASCII abcde xyz
German ├ñ├Â├╝ ├ä├û├£ ├ƒ
Polish ąęźżńł
Russian ð░ð▒ð▓ð│ð┤ðÁð ÐìÐÄÐÅ
CJK õ¢áÕÑ¢
= bom
´╗┐ASCII abcde xyz
German ├ñ├Â├╝ ├ä├û├£ ├ƒ
Polish ąęźżńł
Russian ð░ð▒ð▓ð│ð┤ðÁð ÐìÐÄÐÅ
CJK õ¢áÕÑ¢
== UTF-16LE
= no bom
A S C I I a b c d e x y z
G e r m a n õ ÷ ³ ─ Í ▄ ▀
P o l i s h ♣☺↓☺z☺|☺D☺B☺
R u s s i a n 0♦1♦2♦3♦4♦5♦6♦ M♦N♦O♦
C J K `O}Y
= bom
■A S C I I a b c d e x y z
G e r m a n õ ÷ ³ ─ Í ▄ ▀
P o l i s h ♣☺↓☺z☺|☺D☺B☺
R u s s i a n 0♦1♦2♦3♦4♦5♦6♦ M♦N♦O♦
C J K `O}Y
== UTF-16BE
= no bom
A S C I I a b c d e x y z
G e r m a n õ ÷ ³ ─ Í ▄ ▀
P o l i s h ☺♣☺↓☺z☺|☺D☺B
R u s s i a n ♦0♦1♦2♦3♦4♦5♦6 ♦M♦N♦O
C J K O`Y}
= bom
■ A S C I I a b c d e x y z
G e r m a n õ ÷ ³ ─ Í ▄ ▀
P o l i s h ☺♣☺↓☺z☺|☺D☺B
R u s s i a n ♦0♦1♦2♦3♦4♦5♦6 ♦M♦N♦O
C J K O`Y}
== UTF-32LE
= no bom
A S C I I a b c d e x y z
G e r m a n õ ÷ ³ ─ Í ▄ ▀
P o l i s h ♣☺ ↓☺ z☺ |☺ D☺ B☺
R u s s i a n 0♦ 1♦ 2♦ 3♦ 4♦ 5♦ 6♦ M♦ N
♦ O♦
C J K `O }Y
= bom
■ A S C I I a b c d e x y z
G e r m a n õ ÷ ³ ─ Í ▄ ▀
P o l i s h ♣☺ ↓☺ z☺ |☺ D☺ B☺
R u s s i a n 0♦ 1♦ 2♦ 3♦ 4♦ 5♦ 6♦ M♦ N
♦ O♦
C J K `O }Y
== UTF-32BE
= no bom
A S C I I a b c d e x y z
G e r m a n õ ÷ ³ ─ Í ▄ ▀
P o l i s h ☺♣ ☺↓ ☺z ☺| ☺D ☺B
R u s s i a n ♦0 ♦1 ♦2 ♦3 ♦4 ♦5 ♦6 ♦M ♦N
♦O
C J K O` Y}
= bom
■ A S C I I a b c d e x y z
G e r m a n õ ÷ ³ ─ Í ▄ ▀
P o l i s h ☺♣ ☺↓ ☺z ☺| ☺D ☺B
R u s s i a n ♦0 ♦1 ♦2 ♦3 ♦4 ♦5 ♦6 ♦M ♦N
♦O
C J K O` Y}
Cependant, que se passe-t-il si nous type
les fichiers qui ont été enregistrés? Ils contiennent exactement les mêmes octets qui ont été imprimés sur la console.
Z:\andrew\projects\sx\1259084>type *.txt
uc-test-UTF-16BE-bom.txt
■ A S C I I a b c d e x y z
G e r m a n õ ÷ ³ ─ Í ▄ ▀
P o l i s h ☺♣☺↓☺z☺|☺D☺B
R u s s i a n ♦0♦1♦2♦3♦4♦5♦6 ♦M♦N♦O
C J K O`Y}
uc-test-UTF-16BE-nobom.txt
A S C I I a b c d e x y z
G e r m a n õ ÷ ³ ─ Í ▄ ▀
P o l i s h ☺♣☺↓☺z☺|☺D☺B
R u s s i a n ♦0♦1♦2♦3♦4♦5♦6 ♦M♦N♦O
C J K O`Y}
uc-test-UTF-16LE-bom.txt
ASCII abcde xyz
German äöü ÄÖÜ ß
Polish ąęźżńł
Russian абвгдеж эюя
CJK 你好
uc-test-UTF-16LE-nobom.txt
A S C I I a b c d e x y z
G e r m a n õ ÷ ³ ─ Í ▄ ▀
P o l i s h ♣☺↓☺z☺|☺D☺B☺
R u s s i a n 0♦1♦2♦3♦4♦5♦6♦ M♦N♦O♦
C J K `O}Y
uc-test-UTF-32BE-bom.txt
■ A S C I I a b c d e x y z
G e r m a n õ ÷ ³ ─ Í ▄ ▀
P o l i s h ☺♣ ☺↓ ☺z ☺| ☺D ☺B
R u s s i a n ♦0 ♦1 ♦2 ♦3 ♦4 ♦5 ♦6 ♦M ♦N
♦O
C J K O` Y}
uc-test-UTF-32BE-nobom.txt
A S C I I a b c d e x y z
G e r m a n õ ÷ ³ ─ Í ▄ ▀
P o l i s h ☺♣ ☺↓ ☺z ☺| ☺D ☺B
R u s s i a n ♦0 ♦1 ♦2 ♦3 ♦4 ♦5 ♦6 ♦M ♦N
♦O
C J K O` Y}
uc-test-UTF-32LE-bom.txt
A S C I I a b c d e x y z
G e r m a n ä ö ü Ä Ö Ü ß
P o l i s h ą ę ź ż ń ł
R u s s i a n а б в г д е ж э ю я
C J K 你 好
uc-test-UTF-32LE-nobom.txt
A S C I I a b c d e x y z
G e r m a n õ ÷ ³ ─ Í ▄ ▀
P o l i s h ♣☺ ↓☺ z☺ |☺ D☺ B☺
R u s s i a n 0♦ 1♦ 2♦ 3♦ 4♦ 5♦ 6♦ M♦ N
♦ O♦
C J K `O }Y
uc-test-UTF-8-bom.txt
´╗┐ASCII abcde xyz
German ├ñ├Â├╝ ├ä├û├£ ├ƒ
Polish ąęźżńł
Russian ð░ð▒ð▓ð│ð┤ðÁð ÐìÐÄÐÅ
CJK õ¢áÕÑ¢
uc-test-UTF-8-nobom.txt
ASCII abcde xyz
German ├ñ├Â├╝ ├ä├û├£ ├ƒ
Polish ąęźżńł
Russian ð░ð▒ð▓ð│ð┤ðÁð ÐìÐÄÐÅ
CJK õ¢áÕÑ¢
La seule chose qui fonctionne est le fichier UTF-16LE, avec une nomenclature, imprimé sur la console via type
.
Si nous utilisons autre chose que type
pour imprimer le fichier, nous obtenons des ordures:
Z:\andrew\projects\sx\1259084>copy uc-test-UTF-16LE-bom.txt CON
■A S C I I a b c d e x y z
G e r m a n õ ÷ ³ ─ Í ▄ ▀
P o l i s h ♣☺↓☺z☺|☺D☺B☺
R u s s i a n 0♦1♦2♦3♦4♦5♦6♦ M♦N♦O♦
C J K `O}Y
1 file(s) copied.
Du fait qu'il copy CON
n'affiche pas correctement Unicode, nous pouvons conclure que la type
commande a une logique pour détecter une nomenclature UTF-16LE au début du fichier et utiliser des API Windows spéciales pour l'imprimer.
Nous pouvons voir cela en ouvrant cmd.exe
dans un débogueur quand il type
sort un fichier:
Après avoir type
ouvert un fichier, il recherche une nomenclature de 0xFEFF
—ie, les octets
0xFF 0xFE
en petit-boutien — et s'il existe une telle nomenclature, type
définit un fOutputUnicode
indicateur interne . Ce drapeau est vérifié plus tard pour décider s'il faut appeler WriteConsoleW
.
Mais c'est le seul moyen d'accéder type
à la sortie Unicode, et uniquement pour les fichiers qui ont des nomenclatures et qui sont en UTF-16LE. Pour tous les autres fichiers et pour les programmes qui n'ont pas de code spécial pour gérer la sortie de la console, vos fichiers seront interprétés en fonction de la page de code actuelle et apparaîtront probablement comme du charabia.
Vous pouvez émuler la façon dont les type
sorties Unicode vers la console dans vos propres programmes comme ceci:
#include <stdio.h>
#define UNICODE
#include <windows.h>
static LPCSTR lpcsTest =
"ASCII abcde xyz\n"
"German äöü ÄÖÜ ß\n"
"Polish ąęźżńł\n"
"Russian абвгдеж эюя\n"
"CJK 你好\n";
int main() {
int n;
wchar_t buf[1024];
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
n = MultiByteToWideChar(CP_UTF8, 0,
lpcsTest, strlen(lpcsTest),
buf, sizeof(buf));
WriteConsole(hConsole, buf, n, &n, NULL);
return 0;
}
Ce programme fonctionne pour imprimer Unicode sur la console Windows en utilisant la page de code par défaut.
Pour l'exemple de programme Java, nous pouvons obtenir un peu de sortie correcte en définissant manuellement la page de code, bien que la sortie soit gâchée de manière étrange:
Z:\andrew\projects\sx\1259084>chcp 65001
Active code page: 65001
Z:\andrew\projects\sx\1259084>java Foo
== UTF-8
= no bom
ASCII abcde xyz
German äöü ÄÖÜ ß
Polish ąęźżńł
Russian абвгдеж эюя
CJK 你好
ж эюя
CJK 你好
你好
好
�
= bom
ASCII abcde xyz
German äöü ÄÖÜ ß
Polish ąęźżńł
Russian абвгдеж эюя
CJK 你好
еж эюя
CJK 你好
你好
好
�
== UTF-16LE
= no bom
A S C I I a b c d e x y z
…
Cependant, un programme C qui définit une page de code Unicode UTF-8:
#include <stdio.h>
#include <windows.h>
int main() {
int c, n;
UINT oldCodePage;
char buf[1024];
oldCodePage = GetConsoleOutputCP();
if (!SetConsoleOutputCP(65001)) {
printf("error\n");
}
freopen("uc-test-UTF-8-nobom.txt", "rb", stdin);
n = fread(buf, sizeof(buf[0]), sizeof(buf), stdin);
fwrite(buf, sizeof(buf[0]), n, stdout);
SetConsoleOutputCP(oldCodePage);
return 0;
}
a une sortie correcte:
Z:\andrew\projects\sx\1259084>.\test
ASCII abcde xyz
German äöü ÄÖÜ ß
Polish ąęźżńł
Russian абвгдеж эюя
CJK 你好
La morale de l'histoire?
type
peut imprimer des fichiers UTF-16LE avec une nomenclature quelle que soit votre page de code actuelle
- Les programmes Win32 peuvent être programmés pour sortir Unicode sur la console, en utilisant
WriteConsoleW
.
- D'autres programmes qui définissent la page de codes et ajustent leur encodage de sortie en conséquence peuvent imprimer Unicode sur la console, quelle que soit la page de codes au démarrage du programme
- Pour tout le reste, vous devrez jouer avec
chcp
, et vous obtiendrez probablement toujours une sortie étrange.
WriteFile
, le nombre de caractères écrits au lieu du nombre d'octets était signalé. . Également en 65001, la lecture des caractères non ASCII échoue dans conhost.exe car elle suppose 1 octet ANSI par code UTF-16 lors de l'appelWideCharToMultiByte
.GetStdHandle(STD_OUTPUT_HANDLE)
et Cstdout
sont des descripteurs de console. En pratique, pour tester une console, vérifiez que celaGetConsoleMode
réussit. N'utilisez pas non plus la_isatty
fonction d' exécution C pour vérifier si un descripteur de fichier d'E / S faible est une console; qui vérifie simplement un périphérique en mode caractère, qui comprendNUL
entre autres. Au lieu de cela, appelez_get_osfhandle
et vérifiez la poignée directement.Type
pour voir votre page de codes actuelle (comme Dewfy l'a déjà dit).
Utilisation
pour voir toutes les pages de codes installées et savoir ce que signifie votre numéro de page de codes.
Vous devez avoir installé le Kit de ressources Windows Server 2003 (fonctionne sur Windows XP) pour l'utiliser
nlsinfo
.la source
nlsinfo
il ne semble pas exister sur mon Windows 7.nlsinfo
n'existe pas non plus sur ma machine Windows XP SP3.nlsinfo
n'existe pas non plus sur la machine Windows 10E.Pour répondre à votre deuxième question re. comment fonctionne l'encodage, Joel Spolsky a écrit un excellent article d'introduction à ce sujet . Fortement recommandé.
la source
La commande CHCP affiche la page de codes actuelle. Il a trois chiffres: 8xx et est différent de Windows 12xx. Donc, en tapant un texte uniquement en anglais, vous ne verrez aucune différence, mais une page de code étendue (comme le cyrillique) sera imprimée à tort.
la source
Je suis frustré depuis longtemps par les problèmes de page de codes Windows et les problèmes de portabilité et de localisation des programmes C qu'ils provoquent. Les articles précédents ont détaillé les problèmes en détail, donc je ne vais rien ajouter à ce sujet.
Pour faire court, j'ai fini par écrire ma propre couche de bibliothèque de compatibilité UTF-8 sur la bibliothèque C standard Visual C ++. Fondamentalement, cette bibliothèque garantit qu'un programme C standard fonctionne correctement, dans n'importe quelle page de code, en utilisant UTF-8 en interne.
Cette bibliothèque, appelée MsvcLibX, est disponible en open source sur https://github.com/JFLarvoire/SysToolsLib . Caractéristiques principales:
Plus de détails dans le fichier Lisezmoi MsvcLibX sur GitHub , y compris comment construire la bibliothèque et l'utiliser dans vos propres programmes.
La section de publication du référentiel GitHub ci-dessus fournit plusieurs programmes utilisant cette bibliothèque MsvcLibX, qui montreront ses capacités. Ex: Essayez mon outil which.exe avec des répertoires avec des noms non ASCII dans le CHEMIN, en recherchant des programmes avec des noms non ASCII et en changeant les pages de codes.
Un autre outil utile est le programme conv.exe. Ce programme peut facilement convertir un flux de données de n'importe quelle page de code à n'importe quelle autre. Sa valeur par défaut est entrée dans la page de codes Windows et sortie dans la page de codes de la console actuelle. Cela permet de visualiser correctement les données générées par les applications Windows GUI (ex: Bloc-notes) dans une console de commande, avec une commande simple comme:
type WINFILE.txt | conv
Cette bibliothèque MsvcLibX n'est en aucun cas complète et les contributions pour l'améliorer sont les bienvenues!
la source
En Java, j'ai utilisé l'encodage "IBM850" pour écrire le fichier. Cela a résolu le problème.
la source