web-dev-qa-db-ja.com

cmd.exeはどのエンコード/コードページを使用していますか?

Windowsでcmd.exeを開くと、どのエンコーディングを使用していますか?

現在どのエンコードを使用しているかを確認するにはどうすればよいですか。それは私の地域の設定に依存しますか、またはチェックするべき環境変数がありますか?

特定のエンコーディングのファイルを入力するとどうなりますか?文字が文字化けしたり(誤ったエンコーディングが使用されたり)、時にはそれがうまくいくことがあります。しかし、何が起こっているのかわからない限り、私は何も信頼していません。誰か説明できますか?

247
danglund

はい、苛立たしいことがあります - 時にはtypeや他のプログラムはちんぷんかんぷんと印刷しますが、時にはそうではありません。

まず第一に、Unicode文字は 現在のコンソールフォントに文字が含まれている場合 だけを表示します。そのため、デフォルトのRasterフォントの代わりにLucida ConsoleのようなTrueTypeフォントを使用してください。

ただし、コンソールのフォントに表示しようとしている文字が含まれていない場合は、意味不明の代わりに疑問符が表示されます。ちょっとおかしなことになると、フォントの設定以外にもさまざまなことが起こります。

プログラムがprintfのような標準のCライブラリI/O関数を使用する場合、プログラムの出力エンコーディングはコンソールの出力エンコーディングと一致する必要があります。 chcpは、現在のコードページを表示および設定します。標準CライブラリI/O関数を使用したすべての出力は、chcpで表示されるコードページにあるかのように扱われます。

プログラムの出力エンコーディングとコンソールの出力エンコーディングを一致させるには、2つの方法があります。

  • プログラムはchcpまたは GetConsoleOutputCP を使用してコンソールの現在のコードページを取得し、そのエンコーディングで出力するように設定することができます。

  • あなたやプログラムは、プログラムのデフォルトの出力エンコーディングと一致させるためにchcpまたは SetConsoleOutputCP を使ってコンソールの現在のコードページを設定することができます。

ただし、Win32 APIを使用するプログラムは、 WriteConsoleW を使用してUTF-16LE文字列を直接コンソールに書き込むことができます。これは、コードページを設定せずに正しい出力を取得する唯一の方法です。また、その関数を使用しているときでも、文字列がUTF-16LEエンコーディングで始まっていない場合、Win32プログラムは正しいコードページを MultiByteToWideChar に渡す必要があります。また、プログラムの出力がリダイレクトされている場合、WriteConsoleWは機能しません。その場合はもっといじる必要があります。

typeは各ファイルの先頭でUTF-16LE Byte Order Mark(BOM) 、つまりバイト0xFF 0xFEをチェックするので、しばらくの間は機能します。そのようなマークが見つかった場合、現在のコードページに関係なく、WriteConsoleWを使用してファイル内のUnicode文字を表示します。しかし、UTF-16LE BOMなしのファイルをtypeする場合、またはWriteConsoleWを呼び出さないコマンドでASCII以外の文字を使用する場合は、コンソールのコードページとプログラムの出力エンコードを互いに一致するように設定する必要があります。


これをどうやって見つけることができるでしょうか。

これがUnicode文字を含むテストファイルです。

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

これは、テストファイルをさまざまなUnicodeエンコードで印刷するためのJavaプログラムです。どんなプログラミング言語でも可能です。 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       õ¢áÕÑ¢

のみ動作するのは、BOM付きの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 BOMを検出するロジックがあり、それを印刷するために特別なWindows APIを使用すると結論付けることができます。

これは、ファイルからtypeに移動するときにデバッガでcmd.exeを開くことで確認できます。

enter image description here

typeはファイルを開いた後、0xFEFFのBOM(つまり、リトルエンディアンの0xFF 0xFE)をチェックし、そのようなBOMがある場合、typeは内部のfOutputUnicodeフラグを設定します。このフラグは後でWriteConsoleWを呼び出すかどうかを決定するためにチェックされます。

しかし、それがtypeにUnicodeを出力させる唯一の方法であり、BOMを持ちUTF-16LEのファイルに対してのみです。他のすべてのファイル、およびコンソール出力を処理するための特別なコードを持っていないプログラムの場合、ファイルは現在のコードページに従って解釈され、文字化けとして表示される可能性があります。

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

このプログラムは、既定のコードページを使用してWindowsコンソールにUnicodeを印刷するために機能します。


サンプル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
…

ただし、Unicode UTF-8コードページを設定するCプログラムは、次のとおりです。

#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は、現在のコードページに関係なく、BOM付きのUTF-16LEファイルを印刷できます。
  • Win32プログラムは、WriteConsoleWを使用して、コンソールにUnicodeを出力するようにプログラムできます。
  • コードページを設定し、それに応じて出力エンコーディングを調整する他のプログラムは、プログラム開始時のコードページの内容にかかわらず、コンソールにUnicodeを印刷できます。
  • それ以外の場合は、chcpをいじる必要がありますが、おそらくまだ変な出力になるでしょう。
364
andrewdotn

タイプ

chcp

あなたの現在のコードページを見るために(Dewfyが既に言ったように)。

つかいます

nlsinfo

インストールされているすべてのコードページを確認し、自分のコードページ番号の意味を確認する。

nlsinfoを使用するには、Windows Server 2003リソースキットをインストールする必要があります(Windows XP上で動作します)。

27

2番目の質問に答えるには、エンコーディングのしくみについて、Joel Spolskyはすばらしい これに関する入門記事 を書きました。強く推奨する。

21
Brian Agnew

コマンドCHCPは現在のコードページを表示します。それは3桁の数字を持っています:8xxとWindows 12xxとは異なります。そのため、英語のみのテキストを入力しても違いはありませんが、(キリル文字のような)拡張コードページは誤って印刷されます。

5
Dewfy

私は長い間、Windowsのコードページの問題と、それらが引き起こすCプログラムの移植性とローカライゼーションの問題に不満を感じていました。これまでの投稿で問題の詳細を詳しく説明してきたので、この点に関しては何も追加しません。

長い話を簡単にすると、結局私はVisual C++標準Cライブラリの上に自分のUTF-8互換ライブラリ層を書いてしまいました。基本的にこのライブラリは、標準CプログラムがどのコードページでもUTF-8を内部的に使用して正しく機能することを保証します。

MsvcLibXと呼ばれるこのライブラリは、 https://github.com/JFLarvoire/SysToolsLib からオープンソースとして入手できます。主な特徴:

  • 通常のchar [] C文字列と標準CライブラリAPIを使用して、UTF-8でエンコードされたCソース。
  • どのコードページでも、main()ルーチンargv []を含むすべてのコードが内部でUTF-8として処理され、標準入力と出力は自動的に正しいコードページに変換されます。
  • Stdio.hファイル関数はすべて、260文字を超えるUTF-8パス名をサポートしています(実際には最大64 KB)。
  • Windowsでは、Visual C++およびMsvcLibXとVisual C++ Cライブラリを使用し、Linuxでは、gccとLinux標準Cライブラリを使用して、#ifdef ... #endifブロックを使用することなく、同じソースをコンパイルおよびリンクできます。
  • Linuxでは一般的だが、Visual C++では見つからないインクルードファイルを追加します。例:unistd.h
  • ディレクトリI/O、シンボリックリンク管理などに欠けている機能を追加します。もちろん、すべてUTF-8をサポートします:-)。

GitHubのMsvcLibX README に、ライブラリの作成方法や自分のプログラムでの使用方法などの詳細が記載されています。

上記のGitHubリポジトリの release section は、このMsvcLibXライブラリを使ったいくつかのプログラムを提供しています。例:PATHにASCII以外の名前のディレクトリを指定してwhich.exeツールを試し、ASCII以外の名前のプログラムを検索し、コードページを変更してください。

別の便利なツールがconv.exeプログラムです。このプログラムは、データストリームを任意のコードページから他のコードページに簡単に変換できます。デフォルトはWindowsコードページで入力され、現在のコンソールコードページで出力されます。これにより、WindowsのGUIアプリケーション(例:メモ帳)で生成されたデータをコマンドコンソールで正しく表示することができます。これは次のような単純なコマンドです。type WINFILE.txt | conv

このMsvcLibXライブラリは決して完全なものではなく、それを改善するための貢献は大歓迎です!

Javaでは、ファイルの書き込みに「IBM850」のエンコードを使用しました。これで問題は解決しました。

0
Neumi