Какую кодировку / кодовую страницу использует cmd.exe? - PullRequest
248 голосов
/ 11 августа 2009

Когда я открываю cmd.exe в Windows, какую кодировку он использует?

Как я могу проверить, какая кодировка используется в данный момент? Зависит ли это от моих региональных настроек или есть какие-то переменные среды, которые нужно проверить?

Что происходит, когда вы набираете файл с определенной кодировкой? Иногда я получаю искаженные символы (используется неправильная кодировка), а иногда это работает. Однако я ничему не доверяю, пока не знаю, что происходит. Кто-нибудь может объяснить?

Ответы [ 6 ]

364 голосов
/ 19 июня 2013

Да, это расстраивает - иногда type и другие программы печатать бред, а иногда нет.

Прежде всего, символы Unicode будут отображаться только , если текущий шрифт консоли содержит символы . Так что используйте шрифт TrueType, например Lucida Console, вместо стандартного шрифта Raster.

Но если шрифт консоли не содержит символа, который вы пытаетесь отобразить, вы увидите знаки вопроса вместо тарабарщины. Когда вы получаете тарабарщину, там больше, чем просто настройки шрифтов.

Когда программы используют стандартные функции ввода-вывода C-библиотеки, такие как printf, , выходная кодировка программы должна соответствовать выходной кодировке консоли , или вы получите бред. chcp показывает и устанавливает текущую кодовую страницу. Все Вывод с использованием стандартных функций ввода-вывода библиотеки C обрабатывается так, как если бы он находился в кодовая страница отображается как chcp.

Сопоставление выходной кодировки программы с выходной кодировкой консоли может быть достигнуто двумя различными способами:

  • Программа может получить текущую кодовую страницу консоли, используя chcp или GetConsoleOutputCP и сконфигурируйте себя для вывода в этой кодировке, или

  • Вы или программа можете установить текущую кодовую страницу консоли, используя chcp или SetConsoleOutputCP для соответствия выходной кодировке программы по умолчанию.

Однако программы, использующие Win32 API, могут напрямую писать строки UTF-16LE на консоль с WriteConsoleW. Это единственный способ получить правильный вывод без установки кодовых страниц. А также даже при использовании этой функции, если строка не в кодировке UTF-16LE для начала программа Win32 должна передать правильную кодовую страницу MultiByteToWideChar. Кроме того, WriteConsoleW не будет работать, если вывод программы перенаправлен; в этом случае нужно больше возиться.

type работает иногда, потому что проверяет начало каждого файла на UTF-16LE метка порядка байтов (Спецификация) , то есть байты 0xFF 0xFE. Если он найдет такой Отметьте, что отображает символы Unicode в файле, используя WriteConsoleW независимо от текущей кодовой страницы. Но при type использовании любого файла без UTF-16LE BOM или для использования не-ASCII символов с любой командой который не вызывает WriteConsoleW - вам нужно будет установить Кодовая страница консоли и выходная кодировка программы соответствуют друг другу.


Как мы можем это выяснить?

Вот тестовый файл, содержащий символы Юникода:

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

Вот Java-программа для распечатки тестового файла в куче разных Unicode кодировки. Это может быть на любом языке программирования; это только печатает ASCII-символы или закодированные байты до 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();
            }
        }
    }
}

Вывод в кодовой странице по умолчанию? Всего мусора!

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}

Однако, что если мы type сохранили файлы? Они содержат точные те же байты, которые были напечатаны на консоли.

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       õ¢áÕÑ¢

Работает only - это файл UTF-16LE с спецификацией, напечатанной на консоль через type.

Если мы используем что-либо кроме type для печати файла, мы получаем мусор:

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.

Из-за того, что copy CON не отображает Unicode правильно, мы можем сделать вывод, что команда type имеет логику для обнаружения спецификации UTF-16LE на начало файла и используйте специальные API-интерфейсы Windows для его печати. ​​

Мы можем увидеть это, открыв cmd.exe в отладчике, когда он переходит к type из файла:

enter image description here

После того, как type открывает файл, он проверяет спецификацию 0xFEFF, т.е. байты 0xFF 0xFE в порядке с прямым порядком байтов - и если есть такая спецификация, type устанавливает внутренний fOutputUnicode флаг. Этот флаг проверяется позже, чтобы решить стоит ли звонить WriteConsoleW.

Но это единственный способ заставить type выводить Unicode и только для файлов которые имеют спецификации и находятся в UTF-16LE. Для всех остальных файлов и программ которые не имеют специального кода для обработки вывода на консоль, ваши файлы будут интерпретируется в соответствии с текущей кодовой страницей и, скорее всего, будет отображаться как тарабарщина.

Вы можете подражать хоw type выводит Unicode на консоль в ваших собственных программах, например:

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

Эта программа работает для печати Unicode на консоли Windows, используя кодовая страница по умолчанию.


Для примера программы на Java мы можем получить немного правильного вывода: установка кодовой страницы вручную, хотя вывод путается странным образом:

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
…

Однако, программа на C, которая устанавливает кодовую страницу 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;
}

имеет правильный вывод:

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

Мораль этой истории?

  • type может печатать файлы UTF-16LE с спецификацией независимо от вашей текущей кодовой страницы
  • Программы Win32 могут быть запрограммированы для вывода Unicode на консоль, используя WriteConsoleW.
  • Другие программы, которые устанавливают кодовую страницу и соответственно корректируют свою выходную кодировку, могут печатать Unicode на консоли независимо от того, какая кодовая страница была при запуске программы
  • Для всего остального вам придется возиться с chcp, и, вероятно, все равно будет получаться странный вывод.
27 голосов
/ 11 августа 2009

Тип

chcp

чтобы увидеть вашу текущую кодовую страницу (как уже сказал Дьюфи).

Используйте

nlsinfo

чтобы увидеть все установленные кодовые страницы и узнать, что означает номер вашей кодовой страницы.

Для использования nlsinfo.

необходим установленный комплект ресурсов Windows Server 2003 (работает в Windows XP).
21 голосов
/ 11 августа 2009

Чтобы ответить на ваш второй запрос повторно. Как работает кодирование, Джоэл Спольски написал замечательную вступительную статью по этому . Настоятельно рекомендуется.

5 голосов
/ 11 августа 2009

Команда CHCP показывает текущую кодовую страницу. Он состоит из трех цифр: 8xx и отличается от Windows 12xx. Поэтому при вводе текста только на английском языке вы не увидите никакой разницы, но расширенная кодовая страница (например, кириллица) будет напечатана неправильно.

3 голосов
/ 20 октября 2016

Я долго разочаровывался проблемами с кодовыми страницами Windows, а также проблемами переносимости и локализации программ на C. В предыдущих постах подробно рассказывалось о проблемах, поэтому я не буду ничего добавлять на этот счет.

Короче говоря, в конечном итоге я написал свой собственный уровень библиотеки совместимости UTF-8 поверх стандартной библиотеки языка C на Visual C ++. По сути, эта библиотека гарантирует, что стандартная программа на C работает правильно, на любой кодовой странице, с внутренним использованием UTF-8.

Эта библиотека, называемая MsvcLibX, доступна как открытый исходный код на https://github.com/JFLarvoire/SysToolsLib. Основные функции:

  • C-источники, закодированные в UTF-8, с использованием обычных строк char [] C и стандартных API-интерфейсов библиотеки C.
  • В любой кодовой странице все внутри вашего кода обрабатывается как UTF-8, включая подпрограмму main () argv [], со стандартным вводом и выводом, автоматически конвертируемым в правильную кодовую страницу.
  • Все функции файла stdio.h поддерживают имена путей UTF-8> 260 символов, на самом деле до 64 КБ.
  • Те же источники могут успешно компилироваться и компоноваться в Windows с использованием библиотек Visual C ++ и MsvcLibX и Visual C ++ C, а в Linux - с использованием стандартной библиотеки C gcc и Linux, без необходимости в блоках #ifdef ... #endif.
  • Добавляет включаемые файлы, распространенные в Linux, но отсутствующие в Visual C ++. Пример: unistd.h
  • Добавляет недостающие функции, такие как функции ввода-вывода в каталогах, управления символьными ссылками и т. Д., Конечно, с поддержкой UTF-8: -).

Подробнее о MsvcLibX README на GitHub , в том числе о том, как собрать библиотеку и использовать ее в своих собственных программах.

В разделе release в вышеуказанном репозитории GitHub есть несколько программ, использующих эту библиотеку MsvcLibX, которые покажут свои возможности. Пример: попробуйте мой инструмент which.exe с каталогами с именами, отличными от ASCII, в PATH, поиск программ с именами, не относящимися к ASCII, и изменение кодовых страниц.

Еще одним полезным инструментом является программа conv.exe. Эта программа может легко конвертировать поток данных из любой кодовой страницы в любую другую. По умолчанию он вводится в кодовой странице Windows и выводится в текущей кодовой странице консоли. Это позволяет правильно просматривать данные, сгенерированные приложениями Windows GUI (например, Notepad) в командной консоли, с помощью простой команды, такой как: type WINFILE.txt | conv

Эта библиотека MsvcLibX ни в коем случае не является полной, и мы приветствуем вклад в ее улучшение!

0 голосов
/ 10 января 2019

В Java я использовал кодировку "IBM850" для записи файла. Это решило проблему.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...