2009-08-11 16 views
228

Quando apro cmd.exe in Windows, quale codifica sta utilizzando?Quale codifica/tabella codici è cmd.exe usando?

Come posso verificare quale codifica è attualmente in uso? Dipende dalle mie impostazioni regionali o ci sono variabili d'ambiente da controllare?

Cosa succede quando si digita un file con una determinata codifica? A volte ottengo caratteri confusi (usata la codifica errata) ea volte funziona in qualche modo. Tuttavia non mi fido di nulla finché non so cosa sta succedendo. Qualcuno può spiegare?

risposta

318

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:

enter image description here

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.
+48

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! –

+2

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

+9

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

20

Per rispondere alla seconda query. come funziona la codifica, Joel Spolsky ha scritto un ottimo introductory article on this. Fortemente raccomandato.

+12

Ho letto e lo so.Tuttavia, su Windows mi sento sempre perso perché il sistema operativo e la maggior parte delle applicazioni sembrano totalmente ignoranti della codifica. – danglund

5

Il comando CHCP mostra la codepage corrente. Ha tre cifre: 8xx ed è diverso da Windows 12xx. Quindi digitando un testo solo in inglese non vedresti alcuna differenza, ma una codepage estesa (come il cirillico) verrà stampata erroneamente.

+5

CHCP non mostra solo 3 cifre, né è nel formato 8 ##. 437 è ad esempio una codifica americana, ed è lo standard de facto sui sistemi inglesi. - 65001 è una codifica Unicode (se richiamo a destra è UTF-8 e 65000 è UTF-7) e può essere scelta. Anche CMD consente di passare alla 1250 code page, ma non so da quando queste code page sono selezionabili. (È sotto Win7.) –

21

Tipo

chcp 

per visualizzare la pagina di codice corrente (come già detto Dewfy).

Usa

nlsinfo 

per vedere tutte le pagine di codice installate e scoprire che cosa significa che il numero di pagina di codice.

È necessario disporre di Windows Server 2003 Resource Kit installato (funziona su Windows   XP) per utilizzare nlsinfo.

+14

È interessante notare che 'nlsinfo' non sembra esistere sul mio Windows 7. – Joey

+2

' nlsinfo' non esiste sul mio computer Windows XP SP3. –

+2

Oh, mi dispiace. Penso che sia fornito con gli strumenti del Resource Kit di Windows Server. L'ho usato un paio di volte sulla mia macchina Windows XP SP3 in precedenza e non sapevo che non era installato di default. –

1

Sono stato frustrato a lungo dai problemi della pagina di codice di Windows e dai problemi di portabilità e localizzazione dei programmi C che causano. I post precedenti hanno dettagliato dettagliatamente i problemi, quindi non aggiungerò nulla in merito.

Per farla breve, alla fine ho finito per scrivere il mio livello di libreria di compatibilità UTF-8 sulla libreria C standard di Visual C++. Fondamentalmente questa libreria garantisce che un programma C standard funzioni correttamente, in qualsiasi pagina di codice, utilizzando internamente UTF-8.

Questa libreria, denominata MsvcLibX, è disponibile come open source al numero https://github.com/JFLarvoire/SysToolsLib. Caratteristiche principali:

  • C fonti codificate in UTF-8, utilizzando le normali stringhe C [] C e le API di libreria C standard.
  • In qualsiasi tabella codici, tutto viene elaborato internamente come UTF-8 nel codice, inclusa la routine main() argv [], con input e output standard automaticamente convertiti nella giusta tabella codici.
  • Tutte le funzioni di file stdio.h supportano i percorsi UTF-8> 260 caratteri, fino a 64 KByte effettivamente.
  • Le stesse origini possono essere compilate e collegate correttamente in Windows utilizzando Visual C++ e MsvcLibX e la libreria Visual C++ C, e in Linux utilizzando la libreria C standard gcc e Linux, senza necessità di #ifdef ... #endif blocchi.
  • Aggiunge i file include in Linux, ma manca in Visual C++. Es: unistd.h
  • Aggiunge funzioni mancanti, come quelle per l'I/O delle directory, la gestione dei link simbolici, ecc. Tutto con supporto per UTF-8 naturalmente :-).

Ulteriori dettagli nel numero MsvcLibX README on GitHub, incluso come creare la libreria e utilizzarla nei propri programmi.

release section nel repository GitHub di cui sopra fornisce diversi programmi che utilizzano questa libreria MsvcLibX, che mostrerà le sue funzionalità. Es: Prova il mio strumento which.exe con le directory con nomi non ASCII nel PERCORSO, cercando programmi con nomi non ASCII e modificando le code page.

Un altro strumento utile è il programma conv.exe. Questo programma può facilmente convertire un flusso di dati da qualsiasi tabella codici a qualsiasi altro. Il suo valore predefinito è inserito nella tabella codici di Windows e viene visualizzato nella tabella codici della console corrente. Ciò consente di visualizzare correttamente i dati generati dalle app della GUI di Windows (ad esempio: Blocco note) in una console comandi, con un semplice comando come: type WINFILE.txt | conv

Questa libreria MsvcLibX non è affatto completa, e i contributi per migliorarlo sono benvenuti!

Problemi correlati