.NET Core での コンソールアプリの文字化けを直す


だいぶ予定が遅れたようだが、 .NET Core 1.0 の RC2 が5月中旬にリリースされた。

2000年に初めて .NET がリリースされてから、 mono が登場したりといったことはあったものの、 16年越しでついに クロスプラットフォームのアプリケーションを作成できる環境が、マイクロソフト公式から提供された。

ということで、さっそく .NET から VS2015 DotNetCore Tools Preview 1 をインストールして、 Hello World を書いてみよう。

using System;
using System.Text;

namespace netcore_console_test_01 {
    public class Program {
        public static void Main(string[] args) {
            Console.WriteLine("はろー わ~るど!");
        }
    }
}

160530_1

…文字化けするぞ!!?

コンソール出力が UTF8 から変更できない?

Console.OutputEncoding をみてみると、System.Text.UTF8Encoding となっている。
Windows のコンソールは、 標準では コードページ 932 Shift-JIS になっているので、 UTF8 で出力された文字が文字化けしてしまうのは当然だ。

とりあえずの応急処置として、 出力を Shift-JIS に変更しようとすると…
Console.OutputEncoding = Encoding.GetEncoding(932);

System.NotSupportedException: No data is available for encoding 932. For information on defining a custom encoding, see the documentation for the Encoding.RegisterProvider method.
   at System.Text.Encoding.GetEncoding(Int32 codepage)

お、おうっ!? 例外が発生するぞ?

どうも、 .NET Core は、標準では Unicode, ASCII, CodePage 28591 (西ヨーロッパ言語) 以外の文字コードをサポートしていないらしい。 (参考: Consoleの文字化け対策 CoreCLR)
日本語などをサポートした System.Text.CodePagesEncodingProvider を利用する必要があるようだ。

ということで、まずは project.json の dependencies に、System.Text.Encoding.CodePages を追加しよう。
(dnx や Full .NET Framework には この参照は不要なので、 netcoreapp1.0 にだけ追加しておく。)

 {
   "version": "1.0.0-*",
   "buildOptions": {
     "emitEntryPoint": true
   },
 
   "dependencies": {
     "Microsoft.NETCore.App": {
       "type": "platform",
       "version": "1.0.0-rc2-3002702"
     }
   },
 
   "frameworks": {
     "netcoreapp1.0": {
-      "imports": "dnxcore50"
+      "imports": "dnxcore50",
+      "dependencies": {
+        "System.Text.Encoding.CodePages": "4.0.1-rc2-24027"
+      }
     }
   }
 }

そして、改めて文字を出力してみる。

using System;
using System.Text;

namespace netcore_console_test_01 {
    public class Program {
        public static void Main(string[] args) {
            Console.WriteLine("はろー わ~るど!");
            Console.WriteLine(Console.OutputEncoding);
            Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
            Console.OutputEncoding = Encoding.GetEncoding(932);
            Console.WriteLine("はろー わ~るど!");
            Console.WriteLine(Console.OutputEncoding);
        }
    }
}

160530_2

よし、今度はエラーにならずに出力された。

コンソールの文字コードを自動で選択させる

しかし、この方法では 強制的に Shift-JIS で出力してしまっているので、 非Windows の環境や 別の言語の環境など、 コンソールが Shift-JIS では逆に文字化けにしてしまう。
できれば、コンソールの文字環境を読んで自動的に文字コードを選択してほしい。

実はなんてことはなく、 Console クラスのいずれのメソッドも呼ぶ前に、 真っ先に Encoding.RegisterProvider に登録 すれば、その後最初に Console のメソッドで文字コードを解決する際に、自動的に適切な文字コードを選んでくれるのだ。

using System;
using System.Text;

namespace netcore_console_test_01 {
    public class Program {
        public static void Main(string[] args) {
            Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
            Console.WriteLine("はろー わ~るど!");
            Console.WriteLine(Console.OutputEncoding);
        }
    }
}

160530_3

ただし、 真っ先に というのがポイントで、たとえば Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); の行が実行される前に、 Console.OutputEncoding のプロパティ値をデバッガーの自動変数などで見てしまうと、 UTF8 で固定されてしまうので注意が必要だ。

OutputEncoding を評価させてしまったが最後、その後は UTF8 が使用され続ける

OutputEncoding を評価させてしまったが最後、その後は UTF8 が使用され続ける

コメントを残す

メールアドレスが公開されることはありません。