it-swarm.com.de

Welche Codierungs-/Codepage verwendet cmd.exe?

Wenn ich cmd.exe in Windows öffne, welche Kodierung wird verwendet?

Wie kann ich überprüfen, welche Kodierung aktuell verwendet wird? Hängt es von meinen regionalen Einstellungen ab oder gibt es zu überprüfende Umgebungsvariablen?

Was passiert, wenn Sie eine Datei mit einer bestimmten Kodierung eingeben? Manchmal bekomme ich verstümmelte Zeichen (falsche Kodierung verwendet) und manchmal funktioniert es irgendwie. Ich vertraue jedoch nichts, solange ich nicht weiß, was los ist. Kann mir jemand erklären?

242
danglund

Ja, es ist frustrierend - manchmal wird bei type und anderen Programmen Kauderwelsch ausgegeben, manchmal nicht.

Zunächst werden Unicode-Zeichen nur angezeigt wenn die aktuelle Konsolenschrift die Zeichen enthält . Verwenden Sie daher eine TrueType-Schriftart wie Lucida Console anstelle der Standard-Raster-Schriftart.

Wenn die Konsolenschriftart jedoch nicht das Zeichen enthält, das Sie anzeigen möchten, werden anstelle von Kauderwelsch Fragezeichen angezeigt. Wenn Sie Kauderwelsch bekommen, gibt es mehr als nur Schrifteinstellungen.

Wenn Programme Standard-E/A-Funktionen der C-Bibliothek wie printf verwenden, muss die Ausgabecodierung des Programms mit der Ausgabecodierung der Konsole übereinstimmenchcp zeigt und setzt die aktuelle Codepage. Alle Ausgaben, die Standard-E/A-Funktionen der C-Bibliothek verwenden, werden so behandelt, als ob sie sich in der von chcp angezeigten Codepage befinden.

Das Anpassen der Ausgabecodierung des Programms an die Ausgabecodierung der Konsole kann auf zwei verschiedene Arten erfolgen:

  • Ein Programm kann die aktuelle Codepage der Konsole mit chcp oder GetConsoleOutputCP abrufen und sich so konfigurieren, dass sie in dieser Codierung ausgegeben wird

  • Sie oder ein Programm können die aktuelle Codepage der Konsole mit chcp oder SetConsoleOutputCP so einstellen, dass sie mit der Standard-Ausgabecodierung des Programms übereinstimmt.

Programme, die Win32-APIs verwenden, können jedoch UTF-16LE-Zeichenfolgen mit WriteConsoleW direkt in die Konsole schreiben. Dies ist die einzige Möglichkeit, eine korrekte Ausgabe zu erhalten, ohne Codepages festzulegen. Und selbst wenn Sie diese Funktion verwenden, muss ein Win32-Programm die richtige Codepage an MultiByteToWideChar übergeben, wenn sich zu Beginn keine Zeichenfolge in der UTF-16LE-Codierung befindet. Außerdem funktioniert WriteConsoleW nicht, wenn die Programmausgabe umgeleitet wird. In diesem Fall ist mehr Fummeln erforderlich.

type funktioniert manchmal, weil es den Start jeder Datei auf UTF-16LE überprüft Byte Order Mark (BOM) , d. H. Die Bytes 0xFF 0xFE. Wenn eine solche Markierung gefunden wird, werden die Unicode-Zeichen in der Datei mit WriteConsoleW unabhängig von der aktuellen Codepage angezeigt. Wenn Sie eine Datei ohne UTF-16LE-Stückliste typeen oder Nicht-ASCII-Zeichen mit einem Befehl verwenden, der nicht WriteConsoleW aufruft, müssen Sie die Codepage der Konsole und die Codierung der Programmausgabe so einstellen, dass sie miteinander übereinstimmen.


Wie können wir das herausfinden?

Hier ist eine Testdatei mit Unicode-Zeichen:

ASCII     abcde xyz
German    äöü ÄÖÜ ß
Polish    ąęźżńł
Russian   абвгдеж эюя
CJK       你好

Hier ist ein Java Programm zum Ausdrucken der Testdatei in einer Reihe verschiedener Unicode-Codierungen. Es könnte in jeder Programmiersprache sein; Es werden nur ASCII Zeichen oder codierte Bytes für stdout ausgegeben.

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

Die Ausgabe in der Standard-Codepage? Gesamtmüll!

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}

Was ist jedoch, wenn wir die Dateien, die gespeichert wurden, type? Sie enthalten genau dieselben Bytes, die auf der Konsole ausgegeben wurden.

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       õ¢áÕÑ¢

Das einzige funktionierende Element ist die UTF-16LE-Datei mit einer Stückliste, die über type an die Konsole gesendet wird.

Wenn wir etwas anderes als type verwenden, um die Datei zu drucken, erhalten wir Müll:

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.

Aufgrund der Tatsache, dass copy CON Unicode nicht korrekt anzeigt, können wir schließen, dass der Befehl type über eine Logik zum Erkennen einer UTF-16LE-Stückliste am Anfang der Datei verfügt und spezielle Windows-APIs zum Drucken verwendet.

Wir können dies sehen, indem wir cmd.exe in einem Debugger öffnen, wenn eine Datei mit type ausgegeben wird:

enter image description here

Nachdem type eine Datei geöffnet hat, sucht es nach einer Stückliste mit 0xFEFF, d. H. Den Bytes 0xFF 0xFE in Little-Endian, und wenn es eine solche Stückliste gibt, setzt type ein internes fOutputUnicode-Flag. Dieses Flag wird später überprüft, um zu entscheiden, ob WriteConsoleW aufgerufen werden soll.

Dies ist jedoch die einzige Möglichkeit, mit type Unicode auszugeben, und dies nur für Dateien mit Stücklisten in UTF-16LE. Für alle anderen Dateien und für Programme, die keinen speziellen Code für die Konsolenausgabe haben, werden Ihre Dateien entsprechend der aktuellen Codepage interpretiert und werden wahrscheinlich als Kauderwelsch angezeigt.

Sie können in Ihren eigenen Programmen wie folgt emulieren, wie type Unicode an die Konsole ausgibt:

#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;
}

Dieses Programm ermöglicht das Drucken von Unicode auf der Windows-Konsole unter Verwendung der Standard-Codepage.


Für das Beispielprogramm Java können wir ein wenig korrekte Ausgabe erhalten, indem wir die Codepage manuell einstellen, obwohl die Ausgabe auf seltsame Weise durcheinander gebracht wird:

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
…

Ein C-Programm, das eine Unicode-UTF-8-Codepage festlegt:

#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;
}

hat die richtige Ausgabe:

Z:\andrew\projects\sx\1259084>.\test
ASCII     abcde xyz
German    äöü ÄÖÜ ß
Polish    ąęźżńł
Russian   абвгдеж эюя
CJK       你好

Die Moral der Geschichte?

  • type kann UTF-16LE-Dateien mit einer Stückliste unabhängig von Ihrer aktuellen Codepage drucken
  • Win32-Programme können mit WriteConsoleW so programmiert werden, dass sie Unicode auf der Konsole ausgeben.
  • Andere Programme, die die Codepage festlegen und ihre Ausgabecodierung entsprechend anpassen, können Unicode auf der Konsole drucken, unabhängig davon, wie die Codepage beim Start des Programms lautete
  • Für alles andere müssen Sie mit chcp herumspielen und werden wahrscheinlich immer noch seltsame Ergebnisse erhalten.
369
andrewdotn

Art

chcp

um Ihre aktuelle Codeseite anzuzeigen (wie Dewfy bereits sagte).

Benutzen

nlsinfo

um alle installierten Codeseiten anzuzeigen und herauszufinden, was Ihre Codeseitennummer bedeutet.

Für die Verwendung von nlsinfo muss das Windows Server 2003 Resource Kit installiert sein (funktioniert unter Windows XP).

27

Zur Beantwortung Ihrer zweiten Frage Wie das Kodieren funktioniert, hat Joel Spolsky einen großartigen einführenden Artikel zu diesem geschrieben. Wärmstens empfohlen.

21
Brian Agnew

Der Befehl CHCP zeigt die aktuelle Codepage. Es hat drei Ziffern: 8xx und unterscheidet sich von Windows 12xx. Wenn Sie also nur einen englischen Text eingeben, werden Sie keinen Unterschied feststellen. Eine erweiterte Codepage (z. B. kyrillisch) wird jedoch falsch gedruckt.

5
Dewfy

Ich war lange Zeit frustriert von Windows-Codeseitenproblemen und den Problemen mit der Portabilität und Lokalisierung von C-Programmen. In den vorherigen Beiträgen wurde ausführlich auf die Probleme eingegangen, daher möchte ich hier nichts hinzufügen.

Kurz gesagt, am Ende schrieb ich meine eigene UTF-8-Kompatibilitäts-Bibliotheksschicht über der Standard-C-Bibliothek von Visual C++. Grundsätzlich stellt diese Bibliothek sicher, dass ein Standard-C-Programm in jeder Codepage richtig funktioniert und UTF-8 intern verwendet.

Diese Bibliothek mit dem Namen MsvcLibX ist als Open Source unter https://github.com/JFLarvoire/SysToolsLib verfügbar. Haupteigenschaften:

  • In UTF-8 codierte C-Quellen, unter Verwendung normaler char [] -C-Zeichenfolgen und Standard-C-Bibliotheks-APIs.
  • In einer beliebigen Codepage wird alles intern als UTF-8 in Ihrem Code verarbeitet, einschließlich der Routine arg () [], wobei Standardeingabe und -ausgabe automatisch in die rechte Codepage konvertiert werden.
  • Alle stdio.h-Dateifunktionen unterstützen UTF-8-Pfadnamen mit mehr als 260 Zeichen, tatsächlich bis zu 64 KByte.
  • Dieselben Quellen können in Windows mit der Bibliothek Visual C++ und MsvcLibX und Visual C++ sowie in Linux mit der Standard-C-Bibliothek von Gcc und Linux erfolgreich kompiliert und verknüpft werden, ohne #ifdef ... #endif-Blöcke zu benötigen.
  • Fügt Include-Dateien hinzu, die in Linux üblich sind, in Visual C++ jedoch fehlen. ZB: unistd.h
  • Fügt fehlende Funktionen hinzu, wie z. B. für Verzeichnis-E/A, symbolisches Link-Management usw., alle natürlich mit UTF-8-Unterstützung :-).

Weitere Informationen finden Sie in der Datei MsvcLibX README auf GitHub , einschließlich der Erstellung und Verwendung der Bibliothek in Ihren eigenen Programmen.

Der Abschnitt release im obigen GitHub-Repository enthält mehrere Programme, die diese MsvcLibX-Bibliothek verwenden, um ihre Fähigkeiten darzustellen. Beispiel: Probieren Sie mein which.exe-Tool mit Verzeichnissen mit Nicht-ASCII-Namen im PATH aus, suchen Sie nach Programmen mit Nicht-ASCII-Namen und ändern Sie die Codeseiten.

Ein weiteres nützliches Tool ist das Programm conv.exe. Dieses Programm kann einen Datenstrom problemlos von jeder Codepage in eine andere konvertieren. Der Standardwert wird in die Windows-Codepage eingegeben und in die aktuelle Konsolen-Codepage ausgegeben. Dadurch können Daten, die von Windows-GUI-Apps (z. B. Notepad) generiert wurden, in der Befehlskonsole mit einem einfachen Befehl wie dem folgenden angezeigt werden: type WINFILE.txt | conv

Diese MsvcLibX-Bibliothek ist keinesfalls vollständig und Beiträge zur Verbesserung sind willkommen!

In Java habe ich "IBM850" zum Schreiben der Datei verwendet. Das hat das Problem gelöst.

0
Neumi