web-dev-qa-db-fra.com

Quelle est la page de codage/code utilisée par cmd.exe?

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?

242
danglund

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 typefichier 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:

enter image description here

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 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 code et ajustent leur codage de sortie en conséquence peuvent imprimer Unicode sur la console, quelle que soit la page de code au démarrage du programme.
  • Pour tout le reste, vous devrez jouer avec chcp, et vous obtiendrez probablement toujours une sortie bizarre.
355
andrewdotn

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.

27
Cagdas Altinkaya

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é.

21
Brian Agnew

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.

5
Dewfy

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:

  • C sources encodées en UTF-8, en utilisant des chaînes de caractères char [] C normales, et API de bibliothèque C standard.
  • Dans toute page de code, tout est traité en interne en tant que UTF-8 dans votre code, y compris la routine main () argv [], avec l'entrée et la sortie standard automatiquement converties en page de code de droite.
  • Toutes les fonctions de fichier stdio.h prennent en charge les noms de chemin UTF-8> 260 caractères, jusqu'à 64 Ko actuellement.
  • Les mêmes sources peuvent être compilées et reliées avec succès dans Windows avec Visual C++, les bibliothèques MsvcLibX et Visual C++ C et sous Linux avec les bibliothèques gcc et Linux standard C, sans nécessiter de blocs #ifdef ... #endif.
  • Ajoute les fichiers d'inclusion communs à Linux, mais manquants dans Visual C++. Ex: unistd.h
  • Ajoute des fonctions manquantes, telles que celles des entrées/sorties de répertoire, de la gestion des liens symboliques, etc., le tout avec le support UTF-8 bien sûr :-).

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.

0
Neumi