👻

Javaプログラムをコマンドプロンプトで実行したら日本語が文字化けして困った!

に公開

はじめに

お疲れさまです!加湿器に足す水の量が少なくなってきました。Meloです。

ほとんど初めて触るJavaで練習がてら簡単なコンソールアプリ(コマンドラインアプリ)を作っていたところ、プログラムを実行した際に一部で文字化け現象が発生したので、その原因と解決策を共有したいと思います。

使用している技術スタック

今回紹介するプロジェクトで使用している技術スタックをざっくりまとめておきます。

言語・環境

  • Java: オブジェクト指向プログラミング言語
  • Windows: 開発・実行環境
  • PowerShell: コマンドライン環境
  • コマンドプロンプト: コマンドライン環境
  • VS Code: コードエディタ

文字エンコーディング関連

  • UTF-8: 国際化された文字エンコーディング
  • Shift-JIS (CP932): Windowsの日本語デフォルトエンコーディング
  • StandardCharsets: Javaの文字エンコーディング定数を提供するクラス

問題の概要

さて、名前を入力すると「Hello, Meloさん!」のように挨拶を返してくれるだけの簡単なプログラムで確認してみましょう。

すると通常の日本語出力(System.out.printlnなど)は問題なく表示されるのに、Scannerを使った日本語の入力だけ、文字化けして「????」のように表示されるという問題が発生しました。

問題のコード

Main.java
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        System.out.println("名前を入力してください");
        Scanner scanner = new Scanner(System.in);
        System.out.print("名前: ");
        // ここで入力された日本語が文字化けして表示される
        String name = scanner.nextLine(); 
        System.out.println("Hello, " + name + "さん!");
        scanner.close();
    }
}

このプログラムを以下の手順で実行します:

  1. まず、上記のコードを任意のファイル名(今回はMain.java)で保存

  2. コマンドプロンプトまたはPowerShellを開き、Main.javaファイルが保存されているディレクトリに移動

  3. 以下のコマンドでJavaファイルをコンパイル

javac Main.java
  1. コンパイルが成功すると、同じディレクトリにMain.classファイルが生成される

  2. 以下のコマンドでプログラムを実行

java Main
  1. プログラムが起動したら、任意の文字(今回は「やまだ」)を入力してEnterキーを押す

実行例

名前を入力してください
名前: やまだ
Hello, ????さん! // 文字化けしている

問題の原因

以下のような状況が確認できました:

  1. Windowsのコンソールエンコーディング:

    • WindowsのコマンドプロンプトやPowerShellは、デフォルトでShift-JIS(CP932)などの日本語エンコーディングを使用(chcpコマンドで確認)
    chcp // コマンドプロンプトの文字コードを確認
    現在のコードページ: 932 // Shift-JIS(CP932)
    
    • 一方、JavaプログラムはデフォルトでUTF-8を使用
  2. Scannerクラスの動作:

    • Scannerクラスは、デフォルトではシステムのエンコーディングを使用して入力を変換
    • Windows環境では、これがShift-JIS系のエンコーディングになるため、UTF-8で入力された日本語が正しく変換されない
  3. 入出力の違い:

    • System.out(出力)は正しく日本語を表示できていた
    • System.in(入力)からのデータが文字化けしていた

つまり、Javaのエンコーディング処理の仕組みと、Windowsのコンソールエンコーディングの違いが原因で、文字化けが発生していたということです。

解決策

文字化けを解消するには、以下の2つのアプローチがあります:

アプローチ1: UTF-8に揃える

すべての層でUTF-8エンコーディングを使用することで文字化けを解消します。

コマンドプロンプト

chcp 65001 // コマンドプロンプトの文字コードをUTF-8に変更
javac -encoding UTF-8 Main.java // コンパイル時にUTF-8を指定
java Main // 実行

PowerShell

[Console]::OutputEncoding = [System.Text.Encoding]::UTF8 // 出力の文字コードをUTF-8に変更
[Console]::InputEncoding = [System.Text.Encoding]::UTF8 // 入力の文字コードをUTF-8に変更
javac -encoding UTF-8 Main.java // コンパイル時にUTF-8を指定
java Main // 実行

Javaプログラム側の記述

Main.java
import java.util.Scanner;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;

public class Main {
    public static void main(String[] args) {
        System.out.println("名前を入力してください");
        // 入力の文字コードをUTF-8に変更
        Scanner scanner = new Scanner(new BufferedReader(new InputStreamReader(System.in, StandardCharsets.UTF_8))); 
        System.out.print("名前: ");
        String name = scanner.nextLine();
        System.out.println("Hello, " + name + "さん!");
        scanner.close();
    }
}

アプローチ2: Shift-JISに揃える

WindowsのデフォルトエンコーディングであるShift-JISに合わせることで文字化けを解消します。

コマンドプロンプト/PowerShellの

chcp 932 // コマンドプロンプトの文字コードをShift-JISに変更
javac Main.java // コンパイル時にShift-JISを指定
java Main // 実行

Javaプログラム側の記述

Main.java
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        System.out.println("名前を入力してください");
        Scanner scanner = new Scanner(System.in);
        System.out.print("名前: ");
        // System.inの後に「, "Shift-JIS"」を追記
        String name = new java.util.Scanner(System.in, "Shift-JIS").nextLine();
        System.out.println("Hello, " + name + "さん!");
        scanner.close();
    }
}

おまけ: VS Codeでの設定

VS Codeのsettings.jsonに以下の設定を追加することで、統合ターミナルでPowerShellを使用する際に自動的にUTF-8エンコーディングを設定できます:

settings.json
{
    "terminal.integrated.defaultProfile.windows": "PowerShell",
    "terminal.integrated.profiles.windows": {
        "PowerShell": {
            "source": "PowerShell",
            "args": [
                "-NoExit",
                "-Command",
                "chcp 65001"
            ]
        }
    }
}

実行結果

文字化けが解消されました!

名前を入力してください
名前: やまだ
Hello, やまださん!

まとめ

Windows環境でのJavaプログラムの日本語文字化け問題は、Windowsのコンソール環境とJavaプログラムのエンコーディングの不一致が原因です:

  1. コンソール環境(コマンドプロンプト/PowerShell)

    • デフォルトでShift-JIS(CP932)を使用
    • 環境によって設定方法が異なる
  2. Javaプログラム

    • デフォルトでUTF-8を使用
    • 入出力のエンコーディングを明示的に指定可能

解決策として今回は、以下の2つのアプローチを紹介しました:

  1. UTF-8に揃える方法

    • コンソール環境の設定(chcp 65001
    • PowerShellの場合は追加設定が必要
    • JavaプログラムでのUTF-8指定
  2. Shift-JISに揃える方法

    • コンソール環境の設定(chcp 932
    • JavaプログラムでのShift-JIS指定

重要なポイントは、すべての層で同じエンコーディングを使用することです。Javaプログラム側の設定だけでなく、実行環境(コンソール)の設定も必要になります。

Java開発、特に日本語などの非ASCII文字を扱う場合は、文字エンコーディングの扱いに気を付けるという新たな視点を持てるようになりました。

弊社では一緒に働く仲間を募集しています!

株式会社コードユニットは 「エンジニアが自由に挑戦し、成長できる環境を創る」 をビジョンに掲げるIT企業です。
モダンな技術スタックを使った開発や、このような技術的課題に日々チャレンジできる環境で、楽しく開発をしています。
私のようなプログラミング初心者も、先輩方のサポートのおかげで日々成長できる環境があります。そんな弊社では以下のような方を募集しています:

  • 新しい技術に挑戦したい方
  • 現状に満足せず、常にスキルアップを目指せる方
  • 知らない情報にアンテナを張っている方
  • ビジョンに共感し、会社と共に成長してくれる方

興味を持っていただけた方は、ホームページからご連絡ください。カジュアル面談も実施していますので、お気軽にお問い合わせください!

参考リンク

株式会社コードユニット

Discussion