Oui, c'est frustrant - parfois type
et d'autres programmes impriment du charabia, et parfois ils ne le font pas.
Tout d'abord, les caractères Unicode ne s'afficheront que si la police de console actuelle contient les caractères . Utilisez donc une police TrueType comme 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 se passe plus que de simples paramètres de police.
Lorsque les programmes utilisent des fonctions d'E / S de bibliothèque C standard comme printf
, le codage de sortie du programme doit correspondre au codage de sortie de la console, sinon vous obtiendrez du charabia. chcp
affiche et définit la page de codes actuelle. Toutes les sorties utilisant des fonctions d'E / S de bibliothèque C standard sont traitées comme si elles se trouvaient dans la page de codes affichée par chcp
.
Faire correspondre l'encodage de sortie du programme avec l'encodage de sortie de la console peut être accompli de deux manières différentes:
Un programme peut obtenir la page de codes actuelle de la console en utilisant chcp
ou
GetConsoleOutputCP
, et se configurer pour sortir dans cet encodage, ou
Vous ou un programme pouvez définir la page de codes actuelle de la console en utilisant chcp
ou
SetConsoleOutputCP
pour faire correspondre l'encodage de sortie par défaut du programme.
Cependant, les programmes qui utilisent les API Win32 peuvent écrire des chaînes UTF-16LE directement sur la console avec
WriteConsoleW
. C'est le seul moyen d'obtenir une sortie correcte sans définir de pages de code. Et même lorsque vous utilisez cette fonction, si une chaîne n'est pas dans le codage UTF-16LE pour commencer, un programme Win32 doit passer la page de code correcte à
MultiByteToWideChar
. En outre, WriteConsoleW
ne fonctionnera pas si la sortie du programme est redirigée; plus de violon est nécessaire dans ce cas.
type
fonctionne une partie du temps car il vérifie le début de chaque fichier pour une marque d'ordre d'octets (BOM) UTF-16LE , c'est-à-dire les octets 0xFF 0xFE
. S'il trouve une telle marque, il affiche les caractères Unicode dans le fichier en utilisant WriteConsoleW
indépendamment de la page de code actuelle. Mais pour type
tout fichier sans nomenclature UTF-16LE, ou pour utiliser des caractères non ASCII avec une commande qui n'appelle pas, WriteConsoleW
vous devrez définir la page de code de la console et le codage de sortie du programme pour qu'ils correspondent.
Comment le découvrir?
Voici un fichier de test contenant des caractères Unicode:
ASCII abcde xyz
German äöü ÄÖÜ ß
Polish ąęźżńł
Russian абвгдеж эюя
CJK 你好
Voici un programme Java pour imprimer le fichier de test dans un tas de codages Unicode différents. Il pourrait être dans n'importe quel langage de programmation; il imprime uniquement des caractères ASCII ou des octets codés vers 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? Déchets totaux!
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 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 õ¢áÕÑ¢
La seule chose 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 ordures:
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.
Du fait qu'il copy CON
n'affiche pas correctement Unicode, nous pouvons conclure que la type
commande a 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 voir cela en ouvrant cmd.exe
dans un débogueur quand il type
sort un fichier:
Après avoir type
ouvert un fichier, il recherche une nomenclature de 0xFEFF
—ie, les octets
0xFF 0xFE
en petit-boutien — et s'il existe une telle nomenclature, type
définit un fOutputUnicode
indicateur interne . Ce drapeau est vérifié plus tard pour décider s'il faut appeler WriteConsoleW
.
Mais c'est le seul moyen d'accéder type
à la sortie Unicode, et uniquement pour les fichiers qui ont des nomenclatures et qui sont en 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 comme du charabia.
Vous pouvez émuler la façon dont les type
sorties Unicode vers la console dans vos propres programmes comme ceci:
#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 imprimer Unicode sur la console Windows en utilisant la page de code par défaut.
Pour l'exemple de programme Java, nous pouvons obtenir un peu de sortie correcte en définissant manuellement la page de code, 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 code 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 une 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 quelle que soit votre page de code 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 codes et ajustent leur encodage de sortie en conséquence peuvent imprimer Unicode sur la console, quelle que soit la page de codes au démarrage du programme
- Pour tout le reste, vous devrez jouer avec
chcp
, et vous obtiendrez probablement toujours une sortie étrange.