Ja, es ist frustrierend - manchmal type
drucken 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. chcp
zeigt 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 chcp
oder
abrufen GetConsoleOutputCP
und sich so konfigurieren, dass sie in dieser Codierung oder ausgegeben wird
Sie oder ein Programm können die aktuelle Codepage der Konsole mithilfe chcp
oder
SetConsoleOutputCP
entsprechend 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 WriteConsoleW
nicht, wenn die Ausgabe des Programms umgeleitet wird. In diesem Fall ist mehr Fummelei erforderlich.
type
funktioniert 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 type
Sie jedoch eine Datei ohne UTF-16LE-Stückliste verwenden oder Nicht-ASCII-Zeichen mit einem Befehl verwenden, der nicht aufgerufen WriteConsoleW
wird, 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 type
die 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 type
zum 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 CON
Unicode nicht korrekt angezeigt wird, können wir schließen, dass der type
Befehl ü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.exe
in einem Debugger öffnen, wenn type
eine Datei ausgegeben wird:
Nach dem type
Öffnen einer Datei wird nach einer Stückliste von - 0xFEFF
dh den Bytes
0xFF 0xFE
in Little-Endian - gesucht und, falls eine solche Stückliste vorhanden ist, type
eine 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 type
Unicode 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
chcp
und werden wahrscheinlich immer noch seltsame Ausgaben erhalten.