Quand j'ouvre cmd.exe dans Windows, quel encodage utilise-t-il?
Comment puis-je vérifier le codage qu'il utilise actuellement? Cela dépend-il de mon paramètre régional ou y a-t-il des variables d'environnement à vérifier?
Que se passe-t-il lorsque vous tapez un fichier avec un certain encodage? Parfois, je reçois des caractères brouillés (encodage incorrect) et parfois ça marche. Cependant, je ne fais confiance à rien tant que je ne sais pas ce qui se passe. Quelqu'un peut-il expliquer?
Oui, c’est frustrant - parfois type
et d’autres programmes D’imprimer du charabia, et parfois non.
Tout d’abord, les caractères Unicode n’afficheront que si la police de la console Current contient les caractères . Utilisez donc Une police TrueType telle que 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 ne se passe pas que des réglages de police.
Lorsque les programmes utilisent les fonctions d’E/S standard de la bibliothèque C telles que printf
, le codage de sortie du programme Doit correspondre au codage de sortie de la console, ouvous obtiendrez du charabia. chcp
affiche et définit la page de codes actuelle. Toutes les sorties Qui utilisent les fonctions d’E/S standard de la bibliothèque C sont traitées comme si elles se trouvaient dans la page de codes Affichée par chcp
.
Faire correspondre le codage de sortie du programme avec le codage de sortie de la console Peut être obtenu de deux manières différentes:
Un programme peut obtenir la page de codes actuelle de la console à l’aide de chcp
ou GetConsoleOutputCP
, et se configurer lui-même pour la sortie dans cet encodage, ou
Vous ou un programme pouvez définir la page de codes actuelle de la console à l’aide de chcp
ou SetConsoleOutputCP
pour correspondre au codage de sortie par défaut du programme.
Toutefois, les programmes qui utilisent des API Win32 peuvent écrire des chaînes UTF-16LE directementsur la console avec WriteConsoleW
. C’est le seul moyen d’obtenir une sortie correcte sans définir de pages de code. Et Même si vous utilisez cette fonction, si une chaîne ne figure pas dans le codage UTF-16LE. Pour commencer, un programme Win32 doit transmettre la page de code correcte à MultiByteToWideChar
. , WriteConsoleW
ne fonctionnera pas si la sortie du programme est redirigée; Plus de bidouillage est nécessaire dans ce cas.
type
fonctionne de temps en temps car il vérifie le début de chaque fichier pour un symbole d'ordre UTF-16LE . Byte (BOM) , c'est-à-dire les octets 0xFF 0xFE
. S'il le trouve. La marque __. affiche les caractères Unicode du fichier à l’aide de WriteConsoleW
, quelle que soit la page de code en cours. Mais lorsque vous utilisez type
fichier sans fichier UTF-16LE, ou que vous utilisez des caractères non-ASCII avec une commande Qui n'appelle pas WriteConsoleW
—, vous devez définir la page de code de la console se correspondre.
Comment pouvons-nous savoir cela?
Voici un fichier de test contenant des caractères Unicode:
ASCII abcde xyz
German äöü ÄÖÜ ß
Polish ąęźżńł
Russian абвгдеж эюя
CJK 你好
Voici un programme Java permettant d’imprimer le fichier de test dans une multitude de codages Différents. Unicode. Cela pourrait être dans n'importe quel langage de programmation; il n’imprime que des caractères ASCII ou des octets codés dans 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? Total des ordures!
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 que ceux 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 õ¢áÕÑ¢
Le seulement 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 déchets:
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.
Étant donné que copy CON
n’affiche pas correctement l’Unicode, nous pouvons conclure que la commande type
dispose d’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 le voir en ouvrant cmd.exe
dans un débogueur lorsqu'il passe à type
Dans un fichier:
Une fois que type
a ouvert un fichier, il vérifie la nomenclature 0xFEFF
—, c'est-à-dire les octets 0xFF 0xFE
dans little-endian. S'il existe une telle nomenclature, type
définit un indicateur Internal fOutputUnicode
. Cet indicateur est coché ultérieurement pour décider S'il faut appeler WriteConsoleW
.
Mais c’est le seul moyen d’obtenir type
pour la sortie Unicode, et uniquement pour les fichiers Qui ont des nomenclatures et sont au format 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 sous la forme Gibberish.
Vous pouvez émuler la manière dont type
génère Unicode vers la console dans vos propres programmes, comme suit:
#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 l’impression Unicode sur la console Windows à l’aide de la page de codes par défaut
Pour l'exemple de programme Java, nous pouvons obtenir un peu de sortie correcte en configurant la page de code manuellement, 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 codes 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 la 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 indépendamment de votre page de codes actuelleWriteConsoleW
.chcp
, et vous obtiendrez probablement toujours une sortie bizarre.Type
chcp
pour voir votre page de code actuelle (comme Dewfy l’a déjà dit).
Utilisation
nlsinfo
pour voir toutes les pages de code installées et savoir ce que signifie le numéro de votre page de code.
Le kit de ressources Windows Server 2003 doit être installé (fonctionne sous Windows XP) pour pouvoir utiliser nlsinfo
.
Pour répondre à votre deuxième question re. comment l'encodage fonctionne, Joel Spolsky a écrit un grand { article d'introduction à ce sujet } _. Fortement recommandé.
La commande CHCP affiche la page de codes actuelle. Il a trois chiffres: 8xx et est différent de Windows 12xx. Donc, si vous tapez un texte en anglais, vous ne verrez aucune différence, mais une page de codes étendue (comme Cyrillic) sera imprimée à tort.
J'ai longtemps été frustré par les problèmes de page de code Windows et par les problèmes de portabilité et de localisation des programmes C qu'ils entraînent. Les articles précédents ont détaillé les problèmes en détail, donc je ne vais rien ajouter à cet égard.
En résumé, 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, quelle que soit la page de code, en utilisant UTF-8 en interne.
Cette bibliothèque, appelée MsvcLibX, est disponible en open source à l’adresse https://github.com/JFLarvoire/SysToolsLib . Caractéristiques principales:
Plus de détails dans le MsvcLibX README sur GitHub , notamment comment construire la bibliothèque et l’utiliser dans vos propres programmes.
La section release 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 PATH, recherchez des programmes avec des noms non-ASCII et modifiez les pages de code.
Un autre outil utile est le programme conv.exe. Ce programme peut facilement convertir un flux de données d'une page de code à une autre. Sa valeur par défaut est entrée dans la page de code Windows et sortie dans la page de code de la console actuelle. Cela permet de visualiser correctement les données générées par les applications de l’interface graphique Windows (ex: Notepad) 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!
En Java, j'ai utilisé le codage "IBM850" pour écrire le fichier. Cela a résolu le problème.