Quale codifica / code page utilizza cmd.exe?


271

Quando apro cmd.exe in Windows, quale codifica utilizza?

Come posso verificare quale codifica sta attualmente utilizzando? 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 (codifica errata utilizzata) e a volte funziona. Tuttavia, non mi fido di nulla finché non so cosa sta succedendo. Qualcuno può spiegare?

Risposte:


389

Sì, è frustrante: a volte typee altri programmi stampano senza senso, a volte no.

Innanzitutto, i caratteri Unicode verranno visualizzati solo se il carattere della console corrente contiene i caratteri . Quindi usa un carattere TrueType come Lucida Console invece del carattere raster predefinito.

Ma se il carattere della console non contiene il carattere che stai cercando di visualizzare, vedrai punti interrogativi anziché incomprensibili. Quando diventi incomprensibile, c'è molto di più delle semplici impostazioni dei caratteri.

Quando i programmi utilizzano funzioni di I / O standard della libreria C come printf, la codifica di output del programma deve corrispondere alla codifica di output della console , altrimenti si otterranno incomprensibili. chcpmostra e imposta la tabella codici corrente. Tutto l'output che utilizza le funzioni I / O della libreria C standard viene trattato come se fosse nella tabella codici visualizzata da chcp.

La corrispondenza della codifica di output del programma con la codifica di output della console può essere realizzata in due modi diversi:

  • Un programma può ottenere la codepage corrente della console usando chcpo GetConsoleOutputCP, e configurarsi per l'output in quella codifica, o

  • Tu o un programma potete impostare la codepage corrente della console usando chcpo SetConsoleOutputCPin modo che corrisponda alla codifica di output predefinita del programma.

Tuttavia, i programmi che utilizzano API Win32 possono scrivere stringhe UTF-16LE direttamente sulla console con WriteConsoleW. Questo è l'unico modo per ottenere l'output corretto senza impostare le tabelle codici. E anche quando si utilizza quella funzione, se una stringa non è nella codifica UTF-16LE per cominciare, un programma Win32 deve passare la codepage corretta a MultiByteToWideChar. Inoltre, WriteConsoleWnon funzionerà se l'output del programma viene reindirizzato; in questo caso è necessario più armeggiare.

typefunziona qualche volta perché controlla l'inizio di ogni file per un contrassegno di ordine di byte (BOM) UTF-16LE , ovvero i byte 0xFF 0xFE. Se trova tale segno, visualizza i caratteri Unicode nel file usando WriteConsoleW indipendentemente dalla tabella codici corrente. Ma quando si typeesegue il inging qualsiasi file senza una DBA UTF-16LE o per l'utilizzo di caratteri non ASCII con qualsiasi comando che non chiama, WriteConsoleWsarà necessario impostare la codepage della console e la codifica dell'output del programma in modo che corrispondano tra loro.


Come possiamo scoprirlo?

Ecco un file di prova contenente caratteri Unicode:

ASCII     abcde xyz
German    äöü ÄÖÜ ß
Polish    ąęźżńł
Russian   абвгдеж эюя
CJK       你好

Ecco un programma Java per stampare il file di prova in una serie di diverse codifiche Unicode. Potrebbe essere in qualsiasi linguaggio di programmazione; stampa solo caratteri ASCII o byte 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 tabella codici predefinita? Immondizia totale!

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, cosa succede se noi typei 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-16LE, con una DBA, stampato sulla console tramite type.

Se usiamo qualcosa di diverso da typestampare il file, otteniamo immondizia:

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 CONnon visualizza correttamente Unicode, possiamo concludere che il typecomando ha una logica per rilevare una DBA UTF-16LE all'inizio del file e usare speciali API di Windows per stamparlo.

Possiamo vederlo aprendo cmd.exeun debugger quando type esce un file:

inserisci qui la descrizione dell'immagine

Dopo aver typeaperto un file, verifica la presenza di una DBA di 0xFEFF—ie, i byte 0xFF 0xFEin little-endian — e se esiste una DBA simile, typeimposta un fOutputUnicodeflag interno . Questo flag viene verificato in seguito per decidere se chiamare WriteConsoleW.

Ma questo è l'unico modo per ottenere typel'output di 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 un codice speciale per gestire l'output della console, i file verranno interpretati in base alla tabella codici corrente e probabilmente verranno visualizzati come incomprensibili.

Puoi emulare in che modo typeoutput Unicode sulla console nei tuoi 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 codici predefinita.


Per il programma Java di esempio, possiamo ottenere un po 'di output corretto impostando manualmente la tabella codici, anche se l'output 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 programma C che imposta una tabella codici 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;
}

ha un output corretto:

Z:\andrew\projects\sx\1259084>.\test
ASCII     abcde xyz
German    äöü ÄÖÜ ß
Polish    ąęźżńł
Russian   абвгдеж эюя
CJK       你好

La morale della storia?

  • type è in grado di stampare file UTF-16LE con una distinta componenti indipendentemente dalla tabella codici corrente
  • I programmi Win32 possono essere programmati per inviare Unicode alla console, usando WriteConsoleW.
  • Altri programmi che impostano la codepage e regolano la loro codifica di output di conseguenza possono stampare Unicode sulla console indipendentemente da quale fosse la codepage all'avvio del programma
  • Per tutto il resto dovrai scherzare chcpe probabilmente otterrai comunque un output strano.

73
Whoa, questa deve essere la risposta più dettagliata che abbia mai visto su SO. Credito extra per le stampe di smontaggio e abilità multilingua! Proprio bello, signore!
attacco aereo,

2
Si potrebbe anche voler studiare l'estensione _setmode specifica per Microsoft (_fileno (stdout), _O_U16TEXT) che è stata introdotta in VS2008. Vedere stackoverflow.com/a/9051543 e stackoverflow.com/a/12015918 e msdn.microsoft.com/en-us/library/tw4k6df8(v=vs.90).aspx Oltre alle differenze portabilità evidenti 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 eventuali osservazioni su _setmode (fd, _O_U16TEXT), sarebbe fantastico.
JasDev,

13
Sebbene questa sia una risposta eccellente, è fuorviante affermare che la console supporta UTF-16. È limitato a UCS-2, vale a dire limitato ai caratteri nel piano multilingue di base (BMP). Quando il server della 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 un WCHAR a 16 bit per cella di caratteri. Una coppia surrogata UTF-16 viene stampata come due personaggi in scatola.
Eryk Sun,

3
@utente200783, il modulo decomposto non è supportato; di solito si può trasformare in un equivalente NFC. Inoltre, la console nelle versioni occidentali non consente di mescolare glifi a larghezza intera e metà larghezza. Inoltre, quando si utilizza la tabella codici 65001 (UTF-8), prima di Windows 8 viene WriteFileriportato il numero di caratteri scritti anziché il numero di byte, pertanto gli scrittori con buffer riprovano più volte i byte "rimanenti" in proporzione al numero di caratteri non ASCII . Sempre nel 65001, la lettura di caratteri non ASCII non riesce in conhost.exe perché presuppone 1 byte ANSI per codice UTF-16 durante la chiamata WideCharToMultiByte.
Eryk Sun,

2
I semplici programmi demo in questa risposta presuppongono che GetStdHandle(STD_OUTPUT_HANDLE)e C stdoutsiano handle di console. In pratica, per verificare la presenza di una console, verificare che l'operazione abbia GetConsoleModeesito positivo. Inoltre, non utilizzare la _isattyfunzione di runtime C per verificare se un descrittore di file I / O basso è una console; che controlla solo un dispositivo in modalità personaggio, che include NULtra gli altri. Invece, chiama _get_osfhandlee controlla direttamente la maniglia.
Eryk Sun,

29

genere

chcp

per vedere la tua code page corrente (come già detto da Dewfy).

Uso

nlsinfo

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

È necessario disporre del kit di risorse di Windows Server 2003 (funziona su Windows XP) per poterlo utilizzare nlsinfo.


19
È interessante notare nlsinfoche non sembra esistere sul mio Windows 7.
Joey,

2
nlsinfoinoltre non esiste sul mio computer con Windows XP SP3.
Thomas Owens,

2
Oh mi dispiace. Penso che venga fornito con gli strumenti di Windows Server Resource Kit. L'ho usato un paio di volte sulla mia macchina Windows XP SP3 in precedenza e non sapevo che non fosse installato di default.
Cagdas Altinkaya,

Ah, questo spiega perché è lì sulla mia macchina Vista, dove ho installato quelli.
Joey,

4
nlsinfoinoltre non esiste sul computer Windows 10E.
Yousha Aleayoub

21

Per rispondere alla tua seconda domanda re. come funziona la codifica, Joel Spolsky ha scritto un ottimo articolo introduttivo su questo . Fortemente raccomandato.


13
L'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 tabella codici corrente. Ha tre cifre: 8xx ed è diversa da Windows 12xx. Quindi digitando un testo solo in inglese non vedresti alcuna differenza, ma una tabella codici estesa (come il cirillico) verrà stampata in modo errato.


5
CHCP non mostra solo 3 cifre né è nel formato 8 ##. 437 è ad esempio una codifica USA ed è lo standard defacto sui sistemi inglesi. - 65001 è una codifica Unicode (se ricordo bene è UTF-8 e 65000 è UTF-7) e può essere scelto. Inoltre, CMD consente ad esempio di passare alla tabella codici 1250, ma non so da quando queste pagine codici sono selezionabili. (È sotto Win7.)
Adam LS

4

Sono stato frustrato a lungo dai problemi della tabella codici di Windows e dai problemi di portabilità e localizzazione dei programmi C che causano. I post precedenti hanno illustrato dettagliatamente i problemi, quindi non aggiungerò nulla al riguardo.

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 assicura che un programma C standard funzioni correttamente, in qualsiasi tabella codici, usando UTF-8 internamente.

Questa libreria, chiamata MsvcLibX, è disponibile come open source su https://github.com/JFLarvoire/SysToolsLib . Caratteristiche principali:

  • Sorgenti C codificate in UTF-8, utilizzando normali stringhe C char [] e API standard della libreria C.
  • In qualsiasi tabella codici, tutto viene elaborato internamente come UTF-8 nel codice, inclusa la routine principale () argv [], con input e output standard convertiti automaticamente nella tabella codici corretta.
  • Tutte le funzioni dei file stdio.h supportano percorsi UTF-8> 260 caratteri, fino a 64 KByte in realtà.
  • Le stesse fonti possono essere compilate e collegate correttamente in Windows usando Visual C ++ e MsvcLibX e Visual C ++ C library, e in Linux usando gcc e Linux C library standard, senza bisogno di blocchi #ifdef ... #endif.
  • Aggiunge i file comuni in Linux, ma mancanti in Visual C ++. Es: unistd.h
  • Aggiunge funzioni mancanti, come quelle per l'I / O della directory, la gestione simbolica dei collegamenti, ecc., Il tutto ovviamente con il supporto UTF-8 :-).

Maggiori dettagli nel README di MsvcLibX su GitHub , incluso come costruire la libreria e usarla nei propri programmi.

La sezione di rilascio nel repository GitHub sopra fornisce diversi programmi che utilizzano questa libreria MsvcLibX, che mostrerà le sue capacità. Esempio: prova il mio tool which.exe con directory con nomi non ASCII nel PERCORSO, ricerca di programmi con nomi non ASCII e modifica di pagine di codice.

Un altro strumento utile è il programma conv.exe. Questo programma può facilmente convertire un flusso di dati da qualsiasi tabella codici a qualsiasi altro. L'impostazione predefinita è input nella code page di Windows e output nella code page della console corrente. Ciò consente di visualizzare correttamente i dati generati dalle app della GUI di Windows (es: Blocco note) in una console di comando, con un semplice comando come:type WINFILE.txt | conv

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


2

In Java ho usato la codifica "IBM850" per scrivere il file. Ciò ha risolto il problema.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.