Ja, es ist frustrierend - manchmal typedrucken andere Programme Kauderwelsch, 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 Konsolenschrift jedoch nicht das Zeichen enthält, das Sie anzeigen möchten, werden anstelle von Kauderwelsch Fragezeichen angezeigt. Wenn Sie Kauderwelsch bekommen, ist mehr los als nur Schriftarteneinstellungen.
Wenn Programme Standard-E / A-Funktionen der C-Bibliothek verwenden printf, z. B. muss die Ausgabecodierung des Programms mit der Ausgabecodierung der Konsole übereinstimmen , da sonst Kauderwelsch auftritt. chcpzeigt und setzt die aktuelle Codepage. Alle Ausgaben, die Standard-E / A-Funktionen der C-Bibliothek verwenden, werden so behandelt, als ob sie sich auf der von angezeigten Codepage befinden chcp.
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 chcpoder
abrufen GetConsoleOutputCPund sich so konfigurieren, dass sie in dieser Codierung oder ausgegeben wird
Sie oder ein Programm können die aktuelle Codepage der Konsole mithilfe chcpoder
SetConsoleOutputCPentsprechend der Standardausgabecodierung des Programms einstellen .
Programme, die Win32-APIs verwenden, können jedoch UTF-16LE-Zeichenfolgen direkt mit in die Konsole schreiben
WriteConsoleW . Dies ist die einzige Möglichkeit, eine korrekte Ausgabe zu erhalten, ohne Codepages festzulegen. Und selbst bei Verwendung dieser Funktion muss ein Win32-Programm die richtige Codepage an übergeben, wenn eine Zeichenfolge zunächst nicht in der UTF-16LE-Codierung enthalten ist
MultiByteToWideChar. Funktioniert auch WriteConsoleWnicht, wenn die Ausgabe des Programms umgeleitet wird. In diesem Fall ist mehr Fummelei erforderlich.
typefunktioniert manchmal, weil der Start jeder Datei auf ein UTF-16LE- Byte-Order-Mark (BOM) überprüft wird , dh auf die Bytes 0xFF 0xFE. Wenn eine solche Markierung gefunden wird, werden die Unicode-Zeichen in der Datei mit angezeigtWriteConsoleW
unabhängig von der aktuellen Codepage angezeigt. Wenn typeSie jedoch eine Datei ohne UTF-16LE-Stückliste verwenden oder Nicht-ASCII-Zeichen mit einem Befehl verwenden, der nicht aufgerufen WriteConsoleWwird, müssen Sie die Konsolencodepage und die Programmausgabecodierung 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 verschiedenen Unicode-Codierungen. Es könnte in jeder Programmiersprache sein; Es werden nur ASCII-Zeichen oder codierte Bytes an gedruckt 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();
}
}
}
}
Die Ausgabe in der Standardcodepage? Totaler Mü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 aber, wenn wir typedie Dateien, die gespeichert wurden? Sie enthalten genau die gleichen Bytes, die auf der Konsole gedruckt 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, was funktioniert, ist eine UTF-16LE-Datei mit einer Stückliste, die über auf die Konsole gedruckt wird type.
Wenn wir etwas anderes als typezum Drucken der Datei verwenden, 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.
Aus der Tatsache, dass copy CONUnicode nicht korrekt angezeigt wird, können wir schließen, dass der typeBefehl über eine Logik verfügt, um eine UTF-16LE-Stückliste am Anfang der Datei zu erkennen und spezielle Windows-APIs zum Drucken zu verwenden.
Wir können dies sehen, indem wir cmd.exein einem Debugger öffnen, wenn type
eine Datei ausgegeben wird:

Nach dem typeÖffnen einer Datei wird nach einer Stückliste von - 0xFEFFdh den Bytes
0xFF 0xFEin Little-Endian - gesucht und, falls eine solche Stückliste vorhanden ist, typeeine interne festgelegtfOutputUnicode Flag gesetzt. Dieses Flag wird später überprüft, um zu entscheiden, ob Sie anrufen möchten WriteConsoleW.
Aber das ist der einzige Weg zu bekommen type Unicode auszugeben, und zwar nur für Dateien mit Stücklisten und UTF-16LE. Für alle anderen Dateien und für Programme, die keinen speziellen Code für die Konsolenausgabe haben, werden Ihre Dateien gemäß der aktuellen Codepage interpretiert und wahrscheinlich als Kauderwelsch angezeigt.
Sie können emulieren, wie typeUnicode in Ihren eigenen Programmen an die Konsole ausgegeben wird, wie folgt:
#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 funktioniert zum Drucken von Unicode auf der Windows-Konsole unter Verwendung der Standardcodepage.
Für das Java-Beispielprogramm 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 korrekte 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 so programmiert werden, dass sie Unicode mithilfe von an die Konsole ausgeben
WriteConsoleW .
- Andere Programme, die die Codepage einstellen und ihre Ausgabecodierung entsprechend anpassen, können Unicode auf der Konsole drucken, unabhängig davon, auf welcher Codepage sich das Programm befand
- Für alles andere müssen Sie herumspielen
chcpund werden wahrscheinlich immer noch seltsame Ausgaben erhalten.