Sì, è frustrante, a volte lo type
e altri programmi non hanno la stampa, a volte no.
Prima di tutto, i caratteri Unicode visualizzeranno solo if the current console font contains the characters. Quindi usa un font TrueType come Lucida Console invece del Carattere Raster predefinito.
Ma se il carattere della console non contiene il carattere che si sta tentando di visualizzare, verranno visualizzati punti interrogativi anziché chiacchiere. Quando non si parla, c'è di più che solo le impostazioni dei caratteri.
Quando i programmi utilizzare le funzioni standard di C-libreria di I/O come printf
, codifica output il programma del deve corrispondere la codifica di uscita della console, o si otterrà senza senso. chcp
mostra e imposta la codepage corrente. Tutto l'output utilizzando le funzioni di I/O della libreria C standard viene trattato come se fosse nella codepage visualizzata da chcp
.
corrispondenza codifica l'output del programma con la codifica di uscita della console può essere realizzato in due modi diversi:
Un programma può ottenere tabella codici corrente della console utilizzando chcp
o GetConsoleOutputCP
, e si configura per l'uscita in che la codifica, o
Voi o un programma può impostare tabella codici corrente della console utilizzando chcp
o SetConsoleOutputCP
per abbinare la codifica di output predefinita del programma.
Tuttavia, i programmi che utilizzano le API Win32 in grado di scrivere stringhe UTF-16 direttamente alla console con WriteConsoleW
. Questo è l'unico modo per ottenere l'output corretto senza l'impostazione delle codepage. E anche quando si utilizza quella funzione, se una stringa non è nella codifica UTF-16LE per iniziare, un programma Win32 deve passare la codepage corretta a MultiByteToWideChar
. Inoltre, WriteConsoleW
non funzionerà se l'output del programma viene reindirizzato; in questo caso è necessario più giocherellare.
type
funziona un po 'del tempo perché controlla l'inizio di ogni file per un UTF-16 Byte Order Mark (BOM), vale a dire il byte 0xFF 0xFE
. Se trova tale contrassegno , visualizza i caratteri Unicode nel file utilizzando WriteConsoleW
indipendentemente dalla codepage corrente. Ma quando type
un file senza una distinta base UTF-16LE o per l'utilizzo di caratteri non ASCII con qualsiasi comando che non chiama WriteConsoleW
, è necessario impostare la codepage della console e la codifica dell'output del programma in modo che corrispondano.
Come possiamo scoprirlo?
Ecco un file di test che contiene caratteri Unicode:
ASCII abcde xyz
German äöü ÄÖÜ ß
Polish ąęźżńł
Russian абвгдеж эюя
CJK 你好
Ecco un programma Java per stampare il file di prova in un mazzo di diversi codifiche Unicode. Potrebbe essere in qualsiasi linguaggio di programmazione; stampa solo i caratteri ASCII o codificati in 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();
}
}
}
}
L'output nella codepage predefinita? Totale spazzatura!
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}
Tuttavia, quello che se type
i file che sono stati salvati? Contengono esattamente gli stessi byte che sono stati stampati sulla 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 õ¢áÕÑ¢
L'unica cosa che funziona è il file UTF-16, con una distinta base, stampata alla console tramite type
.
Se usiamo qualcosa di diverso type
per stampare il file, si ottiene spazzatura:
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.
Dal fatto che copy CON
non viene visualizzata correttamente Unicode, possiamo concludere che il comando type
ha una logica per rilevare una distinta base UTF-16LE all'avvio del file e utilizzare le API di Windows speciali per stamparla.
Possiamo vedere questo con l'apertura di cmd.exe
in un debugger quando si va a type
estrarre un file:
Dopo type
apre un file, si verifica la presenza di una distinta base di 0xFEFF
-cioè, la byte 0xFF 0xFE
in little-endian e, se esiste una BOM, type
imposta un flag fOutputUnicode
interno. Questo flag viene controllato in seguito per decidere se chiamare WriteConsoleW
.
Ma questo è l'unico modo per ottenere type
per l'output Unicode e solo per i file che hanno BOM e sono in UTF-16LE. Per tutti gli altri file e per i programmi che non dispongono di codice speciale per gestire l'output della console, i tuoi file saranno interpretati in in base alla codepage corrente e probabilmente si presenteranno come incomprensibili come .
è possibile emulare come type
uscite Unicode alla console nei vostri programmi in questo modo:
#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;
}
Questo programma funziona per la stampa Unicode sulla console di Windows utilizzando la tabella di codici di default.
Per il programma di esempio Java, si può ottenere un po 'di uscita corretta dalla sull'impostazione del codice manualmente, anche se l'uscita viene incasinato in modi strani:
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
…
Tuttavia, un C programma che stabilisce un Unicode UTF-8 tabella codici:
#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;
}
ha output corretto:
Z:\andrew\projects\sx\1259084>.\test
ASCII abcde xyz
German äöü ÄÖÜ ß
Polish ąęźżńł
Russian абвгдеж эюя
CJK 你好
La morale della storia?
type
possibile stampare file UTF-16, con una distinta indipendentemente dalla vostra tabella codici corrente programmi
- Win32 possono essere programmati per l'uscita Unicode alla console, utilizzando
WriteConsoleW
.
- Altri programmi che definiscono la tabella di codici e regolare la loro codifica uscita di conseguenza in grado di stampare Unicode sulla console indipendentemente da ciò che la tabella di codici è stato quando il programma è iniziato
- Per tutto il resto si dovrà pasticciare con
chcp
, e probabilmente ancora ottenere risultati strani.
Whoa, questa deve essere la risposta più dettagliata che abbia mai visto su SO. Credito extra per le stampe di smontaggio e abilità multilingue! Semplicemente bello, signore! –
Si potrebbe anche voler studiare l'estensione specifica Microsoft _setmode (_fileno (stdout), _O_U16TEXT) che è stata introdotta in VS2008. Vedere http://stackoverflow.com/a/9051543 e http://stackoverflow.com/a/12015918 e http://msdn.microsoft.com/en-us/library/tw4k6df8(v=vs. 90) .aspx Oltre alle ovvie differenze di portabilità tra _setmode() e SetConsoleOutputCP(), potrebbero esserci anche altre sottigliezze ed effetti collaterali nascosti in entrambi gli approcci che non sono completamente compresi a prima vista. Se andrewdotn potesse aggiornare la sua risposta con qualsiasi osservazione su _setmode (fd, _O_U16TEXT), sarebbe grandioso. – JasDev
Sebbene questa sia una risposta eccellente, è fuorviante affermare che la console supporta UTF-16. È limitato a UCS-2, cioè limitato ai caratteri nel piano multilingue di base (BMP). Quando il console console Win32 (conhost.exe, al giorno d'oggi) è stato progettato intorno al 1990, Unicode era uno standard a 16 bit, quindi il buffer dello schermo della console utilizza una cella WCHAR a 16 bit per carattere. Una coppia di surrogati UTF-16 stampa come due caratteri di casella. – eryksun