はじめに
業務で Spring Boot のアプリを VS Code のターミナルから動かしていたら、ログの日本語がこんな感じで全部化けました。
縺励£縺励◆繧ィ繝ゥ繝シ...
プログラミングを始めたばかりで、最初は何が起きているのか全然わかりませんでした。調べたり人に聞いたりして、やっと「文字コードのすれ違いが原因らしい」とわかったのですが、そこからも1か所直しては直らず…を繰り返し、結局3か所いじってようやく解決しました。また同じことで悩まないように残しておきます。
環境
- Windows 11
- VS Code(統合ターミナルを使用)
- Windows PowerShell 5.1
- Gradle で起動する Spring Boot(Java 21)
- チームで Git(GitHub)を使って開発
結論(これで直りました)
VS Code の設定ファイル .vscode/settings.json に、以下を書いたら直りました。
{
// ①【UTF-8 で開くターミナルを新しく定義する】原因1と原因2の対策
"terminal.integrated.profiles.windows": { // Windows 用のターミナル一覧に追加する、という設定
"PowerShell (UTF-8)": { // このターミナルの名前。自分で好きに付けてよい(②でこの名前を指定する)
"source": "PowerShell", // 中身は普通の Windows PowerShell を使う、という指定
// ターミナルを開くときに渡す起動オプション(内容は下のコメント参照)
"args": ["-NoExit", "-Command", "chcp 65001 > $null; [Console]::OutputEncoding = [System.Text.Encoding]::UTF8"]
// -NoExit → コマンド実行後もターミナルを閉じない(開いたまま作業できるように)
// -Command → このあとの文字列をコマンドとして実行する、という合図
// chcp 65001 → コンソールの文字コードを UTF-8(=65001) に切り替える(原因1の対策)
// > $null → chcp が出す「現在のコード ページ: 65001」という余計なメッセージを捨てる(画面に出さない)
// ; → 前のコマンドと次のコマンドを続けて実行するための区切り
// [Console]::OutputEncoding = ...UTF8 → PowerShell が出力を読み取るときの文字コードも UTF-8 に固定(原因2の対策・本命)
}
},
// ②【①で作ったターミナルを、VS Code を開いたとき最初から使う】
"terminal.integrated.defaultProfile.windows": "PowerShell (UTF-8)", // ①で付けた名前と同じ文字列を書く
// ③【ターミナルから起動するプログラムに環境変数を渡す】原因3の対策
"terminal.integrated.env.windows": { // Windows で、このターミナルから起動するプロセスに渡す環境変数
"JAVA_TOOL_OPTIONS": "-Dstdout.encoding=UTF-8 -Dstderr.encoding=UTF-8"
// JAVA_TOOL_OPTIONS → Java 起動時に自動で渡されるオプションを入れておくための環境変数
// -Dstdout.encoding=UTF-8 → アプリの「通常の出力(標準出力)」を UTF-8 で書くようにする
// -Dstderr.encoding=UTF-8 → アプリの「エラー用の出力(標準エラー出力)」を UTF-8 で書くようにする
}
}
備考:
.vscode/は.gitignoreに入れておくのがおすすめです。
.gitignoreは「このファイルは Git で共有しない(=チームのリポジトリに上げない)」ものを書いておくファイルです。このファイル内に.vscode/と記載すれば、.vscode配下にあるファイルの設定は自分のPCだけに効いて、チームの他の人には影響しません。
.gitignoreの仕組み:.gitignoreというファイル名が、Gitにとって特別な意味を持つ合言葉になっています。なので、
.gitignoreという名前でテキストファイルを作る- それをプロジェクトのフォルダに置く(普通は一番上の階層=ルート)
- 中に「無視したいもの」を1行ずつ書く
これだけで、Gitは自動的にそのファイルを読んで、書かれたものを共有対象から外すようになります。「有効にするコマンド」を打つ必要はありません。ファイルを置いた時点で効きます。
(多くのプロジェクトでは雛形が最初から.gitignoreを用意してくれているので、その場合は追記するだけでOKです。)
直したのは3か所(原因が3つあった)
調べてみると、ログの文字が画面に出るまでに何段階か受け渡しされていて、そのどの段階でも「Shift-JIS で書かれた文字だ」と解釈されると化ける、ということでした。日本語Windowsでは、いろいろな場所の初期設定が Shift-JIS になっているのが原因です。今回すれ違っていたのは次の3か所でした(上の設定ファイルの①〜③に対応します)。
原因1:ターミナル自体の文字コード設定
日本語Windowsのターミナルは、初期状態が Shift-JIS です。chcp 65001 で UTF-8 に変えます。ただし、これだけでは直りませんでした。
→ 設定ファイル①の中の chcp 65001 の部分
原因2:PowerShell が出力を読み取るときの文字コード(ここが本命でした)
Windows PowerShell 5.1 は、Gradle や Java が出した文字を [Console]::OutputEncoding という設定に従って読み取ります。この初期値も Shift-JIS。なので、アプリが正しく UTF-8 で出力していても、PowerShell 側が Shift-JIS のつもりで読んでしまい、化けます。chcp は表示側の設定なので、この読み取り側は直してくれません。ここに一番ハマりました。
→ 設定ファイル①の中の [Console]::OutputEncoding = ... の部分
原因3:アプリ(Java)側の出力
gradlew bootRun はアプリを別プロセスとして起動しますが、その Java が出力を Shift-JIS で書いてしまうことがあります。JAVA_TOOL_OPTIONS で UTF-8 を指定して直しました。ログの大半は原因1・2で直ったので、これは仕上げという感じでした。
→ 設定ファイル③の JAVA_TOOL_OPTIONS
メモ:化け方の見た目で、だいたい原因の見当がつく
文字化けは「本当は何の文字コードなのか」と「何の文字コードだと思って読んだか」の組み合わせで、見た目が変わります。見た目で当たりをつけられると調べやすいので、代表的なパターンをメモしておきます。
| 化け方の例 | だいたいの原因 |
|---|---|
縺励£(縺・繧・蟄 などが多い) |
UTF-8 の文字を Shift-JIS だと思って読んだ(← 今回のパターン) |
ãã‚ã(ã・â などが多い) |
UTF-8 の文字を Latin-1(西欧の文字コード)だと思って読んだ |
????? や □□□、�
|
読めたけれど、表示先にその文字が無くて置き換えられた |
※あくまで目安ですが、縺 系を見たら「UTF-8 を Shift-JIS で読んでるな」と疑えるようになりました。
おわりに
文字化け=ただの表示の問題だと思っていたのですが、実際は「受け渡しの途中の解釈を全部 UTF-8 にそろえる」問題でした。1か所ずつ試して沼にハマったので、同じ環境の人は最初から3つまとめて設定するのがおすすめです。