PowerShell 7のコードページと$OutputEncodingと[Console]::OutputEncodingについて
背景
PowerShellをバージョン5から7にアップデートして、文字化け問題に悩まされました。
で、文字化けはとりあえず解消できたからいいものの、結局何が原因だったのかはいまいちよくわからない。
とりあえず検証したことをメモとして残しておこうって感じの記事です。
解決法
とりあえず先に解決法を。以下のコマンドで解決しました。
[Console]::OutputEncoding = [System.Text.Encoding]::GetEncoding('utf-8')
これをすれば文字化けが治るはずです。chcp 65001
は必要なし。
PowerShell 5までの文字化けと対処法
utf-8で書かれたC++ソースをコンパイルして実行すると、日本語が含まれる標準出力は文字化けしてました。
これは、テキストがutf-8で書かれていたのに対し、コンソール上での文字エンコード方式がShift-jisとなっていたため、エンコーディングの不一致が生じていて文字化けが起きるというわけです(と思ってます)。
したがって、コンソール上のエンコーディング方式をutf-8に変えれば解決です。
これはchcp 65001
でok。
PowerShell 7以降
chcp 65001
では文字化けは解消しませんでした。
#include <iostream> int main(){ std::cout << "明日の天気は晴れです。\n"; return 0; }
実行結果が次。
譏取律縺ョ螟ゥ豌励・譎エ繧後〒縺吶・
コードページがデフォルトの932でも、65001でも同じように文字化けすることが確認できました。
文字化けを直す
Powershell 7ではコンソールへの標準出力の文字化けを直すために以下のコマンドを実行する必要があるようです。
[Console]::OutputEncoding = [System.Text.Encoding]::GetEncoding('utf-8')
このコードはコンソール上のエンコーディング方式をutf-8にしてくれるものです。
どうやら[Console]::OutputEncoding
が、コンソール上のエンコード方式を表すPowershellの設定変数(Preference Variable)のようです。
これにutf-8にあたるエンコード方式を代入すれば解決なのですが、残念なことに[Console]::OutputEncoding = 'utf-8'
などは通りません。
代入をできるようにするために[System.Text.Encoding]::GetEncoding()
を'utf-8'にかましてあげます。
これでutf-8をコンソール上のエンコード方式に設定できます。
'utf-8'という文字列そのものが[Console]::OutputEncoding
に代入できない原因は、型の違いにあるようです。
曰く、[Console]::OutputEncoding
は「エンコード方式を示す型」のようなものであり、'utf-8'はstring型なので、型の不一致により代入ができないという......。
[System.Text.Encoding]::GetEncoding()
はstring型を受け取りそれに対応する「エンコード方式を示す型」を返す関数なのでしょう。
検証
[Console]::OutputEncoding
がどうやらコンソール上での文字エンコード方式を表しているということはわかりましたが、
だとしたらコードページとはいったい何なのか......
あともう一つ、似た名前の$OutputEncoding
という設定変数も文字エンコードに関わっていそうですが、これもよくわからず。
とりあえず、コードページと$OutputEncoding
、そして[Console]::OutputEncoding
の値をいろいろと変えて検証してみました。
./a
で上記ソースをコンパイルしたものの実行、cat
で上記ソースの表示、あとパス内の日本語名ディレクトリが文字化けするかどうかを調べます。
PowerShell 7の文字化け表
- | chcp 932 $OE =utf-8[Con] =sjis |
65001 utf-8 sjis |
932 utf-8 utf-8 |
65001 utf-8 utf-8 |
932 sjis sjis |
65001 sjis sjis |
932 sjis utf-8 |
65001 sjis utf-8 |
---|---|---|---|---|---|---|---|---|
./a |
× | × | 〇 | 〇 | × | × | 〇 | 〇 |
cat |
〇 | 〇 | 〇 | 〇 | 〇 | 〇 | 〇 | 〇 |
パス | 〇 | 〇 | 〇 | 〇 | 〇 | 〇 | 〇 | 〇 |
($OutputEncoding
を$OE
、[Console]::OutputEncoding
を[Con]
に略記、一列目以降省略してます)
表中の×が文字化け、〇が正常に表示できている状態です。
こうしてみると、コードページと$OutputEncoding
が特に機能している様子はなく、やはり[Console]::OutputEncoding
がコンソールの文字エンコーディングを表しているようです。
こちらの記事を読むに、$OutputEncoding
はパイプでデータを渡すときの文字エンコード方式のようですね。
ついでに、PowerShell 5でも同じことをテストしてみました。
PowerShell 5の文字化け表
- | chcp 932 $OE =utf-8[Con] =sjis |
65001 utf-8 sjis |
932 utf-8 utf-8 |
65001 utf-8 utf-8 |
932 sjis sjis |
65001 sjis sjis |
932 sjis utf-8 |
65001 sjis utf-8 |
---|---|---|---|---|---|---|---|---|
./a |
× | 〇 | 〇 | 〇 | × | 〇 | 〇 | 〇 |
cat |
× | × | × | × | × | × | × | × |
パス | 〇 | 〇 | 〇 | 〇 | 〇 | 〇 | 〇 | 〇 |
こっちはコードページが機能しているように見えます。cat
の文字化けが直っていないのが個人的に気になる。
[Console]::OutputEncoding
がshift-jisでコードページも932のときは必ず文字化けしてます。
この状態で[Console]::OutputEncoding
をutf-8にするかコードページを65001にすると文字化けが解消しているので、やはりこの2つはコンソール上の文字エンコードにかんでそうな雰囲気がします。
左から5,6,7番目の例がわかりやすいです。
しかしcat
の文字化けはこれらを設定するだけでは直りそうになかったです。どうするのがいいんだろう。
[2021/07/14] 文字化けを直すコマンドについて詳しい説明を記述していなかったため追記。