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.
WriteFile
die Anzahl der geschriebenen Zeichen anstelle der Anzahl der Bytes gemeldet, sodass gepufferte Writer die verbleibenden Bytes im Verhältnis zur Anzahl der Nicht-ASCII-Zeichen mehrmals wiederholen . Auch in 65001 schlägt das Lesen von Nicht-ASCII-Zeichen in conhost.exe fehl, da beim Aufruf 1 ANSI-Byte pro UTF-16-Code angenommen wirdWideCharToMultiByte
.GetStdHandle(STD_OUTPUT_HANDLE)
und Cstdout
Konsolenhandles sind. Überprüfen Sie in der Praxis, ob eine KonsoleGetConsoleMode
erfolgreich ist. Verwenden Sie die C-Laufzeitfunktion auch nicht, um_isatty
zu überprüfen, ob ein Dateideskriptor für niedrige E / A eine Konsole ist. das sucht nur nach einem Gerät im Zeichenmodus, zu demNUL
unter anderem gehört. Rufen Sie stattdessen_get_osfhandle
das Handle direkt an und überprüfen Sie es.Art
um Ihre aktuelle Codepage zu sehen (wie Dewfy bereits sagte).
Verwenden
um alle installierten Codepages anzuzeigen und herauszufinden, was Ihre Codepage-Nummer bedeutet.
Für die Verwendung muss das Windows Server 2003 Resource Kit installiert sein (funktioniert unter Windows XP)
nlsinfo
.quelle
nlsinfo
scheint es auf meinem Windows 7 nicht zu existieren.nlsinfo
existiert auch nicht auf meinem Windows XP SP3-Computer.nlsinfo
existiert auch nicht auf einem Windows 10E-Computer.Um Ihre zweite Frage zu beantworten. Joel Spolsky hat einen großartigen Einführungsartikel dazu geschrieben . Wärmstens empfohlen.
quelle
Der Befehl CHCP zeigt die aktuelle Codepage an. Es hat drei Ziffern: 8xx und unterscheidet sich von Windows 12xx. Wenn Sie also einen Text nur auf Englisch eingeben, sehen Sie keinen Unterschied, aber eine erweiterte Codepage (wie Kyrillisch) wird falsch gedruckt.
quelle
Ich war lange frustriert von Problemen mit der Windows-Codepage und den damit verbundenen Problemen mit der Portabilität und Lokalisierung von C-Programmen. In den vorherigen Beiträgen wurden die Probleme ausführlich beschrieben, daher werde ich diesbezüglich nichts hinzufügen.
Um es kurz zu machen, schließlich schrieb ich meine eigene UTF-8-Kompatibilitätsbibliotheksschicht über die Visual C ++ - Standard-C-Bibliothek. Grundsätzlich stellt diese Bibliothek sicher, dass ein Standard-C-Programm in jeder Codepage mit UTF-8 intern einwandfrei funktioniert.
Diese Bibliothek mit dem Namen MsvcLibX ist als Open Source unter https://github.com/JFLarvoire/SysToolsLib verfügbar . Haupteigenschaften:
Weitere Details in der MsvcLibX-README-Datei auf GitHub , einschließlich der Erstellung und Verwendung der Bibliothek in Ihren eigenen Programmen.
Das Release-Bereich im obigen GitHub-Repository enthält mehrere Programme, die diese MsvcLibX-Bibliothek verwenden und deren Funktionen zeigen. Beispiel: Probieren Sie mein Tool which.exe mit Verzeichnissen mit Nicht-ASCII-Namen im PATH aus, suchen Sie nach Programmen mit Nicht-ASCII-Namen und ändern Sie die Codepages.
Ein weiteres nützliches Tool ist das Programm conv.exe. Dieses Programm kann problemlos einen Datenstrom von einer beliebigen Codepage in eine andere konvertieren. Die Standardeinstellung ist die Eingabe in die Windows-Codepage und die Ausgabe in der aktuellen Konsolencodepage. Auf diese Weise können von Windows-GUI-Apps (z. B. Notepad) generierte Daten in einer Befehlskonsole mit einem einfachen Befehl wie dem folgenden korrekt angezeigt werden:
type WINFILE.txt | conv
Diese MsvcLibX-Bibliothek ist keineswegs vollständig, und Beiträge zur Verbesserung sind willkommen!
quelle
In Java habe ich die Codierung "IBM850" verwendet, um die Datei zu schreiben. Das hat das Problem gelöst.
quelle