Qual codificação / página de código é cmd.exe usando?

Quando abro o cmd.exe no Windows, que codificação ele está usando?

Como posso verificar qual codificação está usando atualmente? Depende da minha configuração regional ou existem variables ​​de ambiente para verificar?

O que acontece quando você digita um arquivo com uma certa codificação? Às vezes eu recebo caracteres ilegíveis (codificação incorreta usada) e às vezes funciona bem. No entanto, não confio em nada, desde que não saiba o que está acontecendo. Alguém pode explicar?

Sim, é frustrante – às vezes, o type e outros programas imprimem jargões e, às vezes, não.

Em primeiro lugar, os caracteres Unicode serão exibidos apenas se a fonte atual do console contiver os caracteres . Portanto, use uma fonte TrueType, como o Lucida Console, em vez da fonte Raster padrão.

Mas se a fonte do console não contiver o caractere que você está tentando exibir, você verá pontos de interrogação em vez de rabiscos. Quando você fica rabugento, há mais coisas acontecendo do que apenas configurações de fonte.

Quando programas usam funções de E / S de biblioteca C padrão, como printf , a codificação de saída do programa deve corresponder à codificação de saída do console , ou você ficará com rabiscos. chcp mostra e define a página de códigos atual. Toda saída usando funções I / O da biblioteca C padrão é tratada como se estivesse na página de código exibida pelo chcp .

A correspondência da codificação de saída do programa com a codificação de saída do console pode ser realizada de duas maneiras diferentes:

  • Um programa pode obter a página de código atual do console usando chcp ou GetConsoleOutputCP e configurar-se para GetConsoleOutputCP essa codificação ou

  • Você ou um programa pode definir a página de código atual do console usando chcp ou SetConsoleOutputCP para corresponder à codificação de saída padrão do programa.

No entanto, programas que usam APIs do Win32 podem gravar seqüências de caracteres UTF-16LE diretamente no console com WriteConsoleW . Essa é a única maneira de obter a saída correta sem definir páginas de códigos. E mesmo quando usar essa function, se uma string não estiver na codificação UTF-16LE para começar, um programa Win32 deve passar a página de código correta para MultiByteToWideChar . Além disso, WriteConsoleW não funcionará se a saída do programa for redirecionada; mais brigas são necessárias nesse caso.

type funciona algumas vezes porque verifica o início de cada arquivo para uma BOM (Byte Order Mark) UTF-16LE, isto é, os bytes 0xFF 0xFE . Se encontrar essa marca, exibirá os caracteres Unicode no arquivo usando WriteConsoleW independentemente da página de códigos atual. Mas ao type qualquer arquivo sem uma BOM UTF-16LE ou para usar caracteres não-ASCII com qualquer comando que não chame WriteConsoleW será necessário definir a página de códigos do console e a codificação de saída do programa para corresponder entre si.


Como podemos descobrir isso?

Aqui está um arquivo de teste contendo caracteres Unicode:

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

Aqui está um programa em Java para imprimir o arquivo de teste em várias codificações Unicode diferentes. Pode estar em qualquer linguagem de programação; apenas imprime caracteres ASCII ou bytes codificados para 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(); } } } } 

A saída na página de códigos padrão? Lixo total!

 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 ASCII abcdexyz G erman õ ÷ ³ ─ Í ▄ ▀ P olish ♣☺↓☺z☺|☺D☺B☺ R ussian 0♦1♦2♦3♦4♦5♦6♦ M♦N♦O♦ CJK `O}Y = bom ■ASCII abcdexyz G erman õ ÷ ³ ─ Í ▄ ▀ P olish ♣☺↓☺z☺|☺D☺B☺ R ussian 0♦1♦2♦3♦4♦5♦6♦ M♦N♦O♦ CJK `O}Y == UTF-16BE = no bom ASCII abcdexyz G erman õ ÷ ³ ─ Í ▄ ▀ P olish ☺♣☺↓☺z☺|☺D☺B R ussian ♦0♦1♦2♦3♦4♦5♦6 ♦M♦N♦O CJKO`Y} = bom ■ ASCII abcdexyz G erman õ ÷ ³ ─ Í ▄ ▀ P olish ☺♣☺↓☺z☺|☺D☺B R ussian ♦0♦1♦2♦3♦4♦5♦6 ♦M♦N♦O CJKO`Y} == UTF-32LE = no bom ASCII abcdexyz G erman õ ÷ ³ ─ Í ▄ ▀ P olish ♣☺ ↓☺ z☺ |☺ D☺ B☺ R ussian 0♦ 1♦ 2♦ 3♦ 4♦ 5♦ 6♦ M♦ N ♦ O♦ CJK `O }Y = bom ■ ASCII abcdexyz G erman õ ÷ ³ ─ Í ▄ ▀ P olish ♣☺ ↓☺ z☺ |☺ D☺ B☺ R ussian 0♦ 1♦ 2♦ 3♦ 4♦ 5♦ 6♦ M♦ N ♦ O♦ CJK `O }Y == UTF-32BE = no bom ASCII abcdexyz G erman õ ÷ ³ ─ Í ▄ ▀ P olish ☺♣ ☺↓ ☺z ☺| ☺D ☺B R ussian ♦0 ♦1 ♦2 ♦3 ♦4 ♦5 ♦6 ♦M ♦N ♦O CJKO` Y} = bom ■ ASCII abcdexyz G erman õ ÷ ³ ─ Í ▄ ▀ P olish ☺♣ ☺↓ ☺z ☺| ☺D ☺B R ussian ♦0 ♦1 ♦2 ♦3 ♦4 ♦5 ♦6 ♦M ♦N ♦O CJKO` Y} 

No entanto, e se type os arquivos salvos? Eles contêm exatamente os mesmos bytes que foram impressos no console.

 Z:\andrew\projects\sx\1259084>type *.txt uc-test-UTF-16BE-bom.txt ■ ASCII abcdexyz G erman õ ÷ ³ ─ Í ▄ ▀ P olish ☺♣☺↓☺z☺|☺D☺B R ussian ♦0♦1♦2♦3♦4♦5♦6 ♦M♦N♦O CJKO`Y} uc-test-UTF-16BE-nobom.txt ASCII abcdexyz G erman õ ÷ ³ ─ Í ▄ ▀ P olish ☺♣☺↓☺z☺|☺D☺B R ussian ♦0♦1♦2♦3♦4♦5♦6 ♦M♦N♦O CJKO`Y} uc-test-UTF-16LE-bom.txt ASCII abcde xyz German äöü ÄÖÜ ß Polish ąęźżńł Russian абвгдеж эюя CJK 你好uc-test-UTF-16LE-nobom.txt ASCII abcdexyz G erman õ ÷ ³ ─ Í ▄ ▀ P olish ♣☺↓☺z☺|☺D☺B☺ R ussian 0♦1♦2♦3♦4♦5♦6♦ M♦N♦O♦ CJK `O}Y uc-test-UTF-32BE-bom.txt ■ ASCII abcdexyz G erman õ ÷ ³ ─ Í ▄ ▀ P olish ☺♣ ☺↓ ☺z ☺| ☺D ☺B R ussian ♦0 ♦1 ♦2 ♦3 ♦4 ♦5 ♦6 ♦M ♦N ♦O CJKO` Y} uc-test-UTF-32BE-nobom.txt ASCII abcdexyz G erman õ ÷ ³ ─ Í ▄ ▀ P olish ☺♣ ☺↓ ☺z ☺| ☺D ☺B R ussian ♦0 ♦1 ♦2 ♦3 ♦4 ♦5 ♦6 ♦M ♦N ♦O CJKO` Y} uc-test-UTF-32LE-bom.txt ASCII abcdexyz G erman ä ö ü Ä Ö Ü ß P olish ą ę ź ż ń ł R ussian а б в г д е ж э ю я CJK 你 好uc-test-UTF-32LE-nobom.txt ASCII abcdexyz G erman õ ÷ ³ ─ Í ▄ ▀ P olish ♣☺ ↓☺ z☺ |☺ D☺ B☺ R ussian 0♦ 1♦ 2♦ 3♦ 4♦ 5♦ 6♦ M♦ N ♦ O♦ CJK `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 õ¢áÕÑ¢ 

A única coisa que funciona é o arquivo UTF-16LE, com uma BOM, impressa no console por type .

Se usarmos algo diferente de type para imprimir o arquivo, temos lixo:

 Z:\andrew\projects\sx\1259084>copy uc-test-UTF-16LE-bom.txt CON ■ASCII abcdexyz G erman õ ÷ ³ ─ Í ▄ ▀ P olish ♣☺↓☺z☺|☺D☺B☺ R ussian 0♦1♦2♦3♦4♦5♦6♦ M♦N♦O♦ CJK `O}Y 1 file(s) copied. 

Pelo fato de a copy CON não exibir Unicode corretamente, podemos concluir que o comando type possui lógica para detectar uma BOM UTF-16LE no início do arquivo e usar APIs especiais do Windows para imprimi-la.

Podemos ver isso abrindo cmd.exe em um depurador quando for type um arquivo:

insira a descrição da imagem aqui

Depois que o type abre um arquivo, ele verifica se há uma BOM de 0xFEFF ou seja, os bytes 0xFF 0xFE em little-endian – e, se houver essa BOM, o type define um sinalizador fOutputUnicode interno. Esse sinalizador é verificado mais tarde para decidir se deve chamar WriteConsoleW .

Mas essa é a única maneira de obter o type de saída Unicode, e apenas para arquivos que possuem BOMs e estão em UTF-16LE. Para todos os outros arquivos e para programas que não possuem código especial para manipular a saída do console, seus arquivos serão interpretados de acordo com a página de códigos atual e provavelmente serão exibidos como ininteligíveis.

Você pode emular como o type envia Unicode para o console em seus próprios programas da seguinte forma:

 #include  #define UNICODE #include  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; } 

Este programa funciona para imprimir Unicode no console do Windows usando a página de códigos padrão.


Para o programa Java de amostra, podemos obter um pouco de saída correta configurando a página de códigos manualmente, embora a saída fique desordenada de maneiras estranhas:

 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 ASCII abcdexyz … 

No entanto, um programa C que define uma página de códigos Unicode UTF-8:

 #include  #include  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; } 

tem saída correta:

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

A moral da história?

  • type pode imprimir arquivos UTF-16LE com uma lista técnica, independentemente da sua página de códigos atual
  • Programas Win32 podem ser programados para saída Unicode para o console, usando WriteConsoleW .
  • Outros programas que definem a página de códigos e ajustam sua codificação de saída de acordo podem imprimir Unicode no console, independentemente de qual página de código foi quando o programa foi iniciado
  • Para tudo o mais, você terá que mexer com o chcp e, provavelmente, ainda obterá resultados estranhos.

Tipo

 chcp 

para ver sua página de código atual (como Dewfy já disse).

Usar

 nlsinfo 

para ver todas as páginas de código instaladas e descobrir o significado do seu número de página de código.

Você precisa ter o kit de resources do Windows Server 2003 instalado (funciona no Windows XP) para usar o nlsinfo .

Para responder sua segunda consulta re. Como a codificação funciona, Joel Spolsky escreveu um ótimo artigo introdutório sobre isso . Fortemente recomendado.

O comando CHCP mostra a página de códigos atual. Tem três dígitos: 8xx e é diferente do Windows 12xx. Então, digitando um texto apenas em inglês, você não verá nenhuma diferença, mas uma página de códigos estendida (como Cirílico) será impressa incorretamente.

Eu tenho sido frustrado por muito tempo por problemas de páginas de código do Windows, e os problemas de portabilidade e localização de programas em C que eles causam. As postagens anteriores detalharam os problemas, então não vou acrescentar nada a esse respeito.

Para encurtar a história, acabei escrevendo minha própria camada de biblioteca de compatibilidade UTF-8 sobre a biblioteca C padrão do Visual C ++. Basicamente, esta biblioteca garante que um programa C padrão funcione corretamente, em qualquer página de código, usando UTF-8 internamente.

Esta biblioteca, chamada MsvcLibX, está disponível como código aberto em https://github.com/JFLarvoire/SysToolsLib . Principais características:

  • Fontes C codificadas em UTF-8, usando strings char [] C normais e APIs da biblioteca C padrão.
  • Em qualquer página de código, tudo é processado internamente como UTF-8 em seu código, incluindo a rotina principal () argv [], com input e saída padrão automaticamente convertidas para a página de código correta.
  • Todas as funções do arquivo stdio.h suportam nomes de caminho UTF-8> 260 caracteres, até 64 KB, na verdade.
  • As mesmas fonts podem compilar e vincular com êxito no Windows usando Visual C ++ e biblioteca MsvcLibX e Visual C ++ C e no Linux usando gcc e biblioteca C padrão do Linux, sem necessidade de #ifdef … #endif blocks.
  • Adiciona arquivos de inclusão comuns no Linux, mas ausentes no Visual C ++. Ex: unistd.h
  • Adiciona funções ausentes, como aquelas para E / S de diretório, gerenciamento de link simbólico, etc, tudo com suporte a UTF-8, é claro :-).

Mais detalhes no README do MsvcLibX no GitHub , incluindo como construir a biblioteca e usá-la em seus próprios programas.

A seção de lançamento no repository GitHub acima fornece vários programas usando essa biblioteca MsvcLibX, que mostrará seus resources. Ex: Tente minha ferramenta which.exe com diretórios com nomes não-ASCII no PATH, procurando programas com nomes não-ASCII e alterando as páginas de códigos.

Outra ferramenta útil é o programa conv.exe. Este programa pode facilmente converter um stream de dados de qualquer página de código para qualquer outro. Seu padrão é a input na página de código do Windows e a saída na página de código atual do console. Isso permite visualizar corretamente os dados gerados por aplicativos GUI do Windows (ex: Bloco de Notas) em um console de comando, com um comando simples como: type WINFILE.txt | conv type WINFILE.txt | conv

Esta biblioteca MsvcLibX não está completa, e contribuições para melhorá-la são bem vindas!