posts
hugo.tomlをメモ帳で直したら文字化けした話(UTF-8・BOM・Shift-JISの違い)
(更新 )Search Consoleにサイトマップを登録しようとしたところから始まった、想像以上に長いトラブルの記録です。たった1行を直すつもりが、設定ファイルの日本語が全部化け、直したと思ったら今度はHugoが動かなくなりました。
先に結論を書いておきます。
- 日本語を含む設定ファイルを、Windowsのメモ帳で編集しない(VSCodeを使い、右下が「UTF-8」になっているか確認する)
- 文字化けして見えても、ファイルが壊れているとは限らない(見るためのコマンド側の問題のこともある)
invalid character ... U+00EF 'ï'というエラーは、ファイルの先頭に付いたBOMが原因
発端:baseURLを1行直したかっただけ
Search Consoleでサイトマップを送ると「サイトマップ アドレスが無効です」と出ました。sitemap.xml を開くと、中のURLが全部 https://example.com/... という仮のドメインのまま。hugo.toml の baseURL が初期値のままだったのが原因です(この経緯は 第8回 に書いています)。
そこで、hugo.toml をメモ帳で開いて baseURL の1行だけ書き換えて保存しました。すると、ファイルの中の日本語が全部こうなりました。
description = "螟ァ蟄ヲ縺ァHTML/CSS繧貞ュヲ繧薙□遲・・′..."
そもそも文字コードとは
コンピュータは文字をそのまま扱えないので、すべての文字を数字に置き換えて保存しています。 「あ」をどの数字にするかという対応表が「文字コード」です。保存したときの対応表と、読むときの対応表がずれると、文字化けが起きます。
| 文字コード | 特徴 |
|---|---|
| Shift-JIS | 昔からある日本語Windowsの標準。1文字を1〜2バイトで表す |
| UTF-8 | 世界中の文字を1つの表で扱える、今の標準。1文字を1〜4バイトで表す |
| UTF-8(BOM付き) | UTF-8の先頭に「これはUTF-8です」という目印(BOM)を付けたもの |
Hugoのファイルは、UTF-8(BOMなし)で保存するのが前提です。
原因の切り分け
これが単純そうに見えて、実は2段階になっていました。
1段階目:Shift-JISとUTF-8の取り違え
元の hugo.toml はUTF-8で書かれていました。それをメモ帳が違う文字コードとして扱って保存したため、日本語が化けました。
上の 螟ァ蟄ヲ縺ァ… は、UTF-8で書かれた文字を、Shift-JISのルールで読んでしまったときに出る、典型的な化け方です。この形の化け方を見たら、「UTF-8とShift-JISの取り違え」を疑うと早いです。
見るコマンドによって、化けたり化けなかったりする
ここでさらに混乱しました。PowerShellでファイルの中身を見ると、コマンドによって結果が違ったのです。
type hugo.toml # 化けて見える
Get-Content hugo.toml -Encoding UTF8 # 正しく見える
type は、ファイルを古い文字コードのつもりで表示しようとする癖があります。同じファイルなのに、見るコマンドによって化けたり化けなかったりするので、type の結果だけを見て「ファイルが壊れた」と決めつけるのは早すぎました。
2段階目:BOMでHugoが止まる
文字コードをUTF-8に合わせて保存し直し、Get-Content で見ても正しくなりました。ところが hugo を打つと、今度はこう言われました。
unmarshal failed: toml: invalid character at start of key: U+00EF 'ï'
原因は、メモ帳が「UTF-8」で保存するときに、ファイルの先頭に目に見えないBOMを付けていたことでした。BOM自体は正しい仕組みですが、hugo.toml の書式(TOML)ではBOMを想定していないので、先頭の見えない文字を「変な文字がある」と判断して止まります。
エラーに出ている U+00EF 'ï' は、BOMの最初の1バイト(EF)を1文字として読んだもの。つまり「ファイルの一番先頭に、見えない何かがある」という意味です。
直し方
そのとき筆者がやった方法:PowerShellでBOMなしで書き出す
メモ帳を通すとまた同じことが起きそうだったので、PowerShellから直接ファイルを書き出しました。
$text = @"
(ファイルの中身をここに)
"@
[System.IO.File]::WriteAllText("$PWD\hugo.toml", $text, (New-Object System.Text.UTF8Encoding $false))
UTF8Encoding $false が「BOMを付けない」という指定です。これで文字化けも、Hugoのエラーも直りました。
今のやり方:VSCodeで開いて、右下を確認する
今は設定ファイルも記事も、すべてVSCodeで編集しています。
- VSCodeでファイルを開く
- 画面の右下に出ている文字コードを見る
- 「UTF-8」になっていればOK。「UTF-8 with BOM」や「Shift JIS」になっていたら、そこをクリック →「エンコード付きで保存」→「UTF-8」を選ぶ
化けた状態で保存してしまった日本語は、あとから文字コードを切り替えても元に戻らないことがあります。筆者も、正しい中身を用意して丸ごと書き出し直しました。編集する前にファイルをコピーしておくと安心です。
その後:まだサイトマップが通らない
文字化けを直し、baseURL を https://noluckblog.com/ にしてサイトマップを送り直しても、まだ「取得できませんでした」でした。ブラウザで https:// で開くと「接続できません」。HTTPS化(証明書の導入)がまだだったのが原因で、第6回 の手順で証明書を入れたあと、ようやく
サイトマップは正常に処理されました
検出されたページ数: 23
となりました。1つ直すと次の問題が出てくる、という展開の連続でしたが、最後に成功が出たときは、それまでで一番達成感がありました。
つまずきポイントのまとめ
| つまずいたこと | 原因 | 学んだこと |
|---|---|---|
| サイトマップが無効と言われた | baseURL が仮のドメインのままだった |
設定ファイルの初期値を見落とさない |
hugo.toml の日本語が全部化けた |
メモ帳がUTF-8のファイルを別の文字コードで保存した | 日本語のファイルはVSCodeで編集し、右下の文字コードを見る |
type では化け、Get-Content では正しく見えた |
type が古い文字コードで表示していた |
「ファイルが壊れた」のか「見る側の問題」なのかを分けて考える |
U+00EF 'ï' でHugoが止まった |
メモ帳が付けたBOM | Hugoのファイルは「UTF-8(BOMなし)」で保存する |
| HTTPSのサイトマップが取得できない | 証明書がまだ入っていなかった | https:// にする前に、証明書を入れる |
普段なにげなく保存している文字が、裏ではこんなに細かいルールで支えられていると実感した出来事でした。
あわせて読みたい
- 【第2回】機材編 — 必要なPC・ソフトと、これから使う4つの道具 — VSCodeを入れる手順
- 【第8回】Google Search Console編 — Googleにサイトを登録する — この事件の発端になったサイトマップの送信
- 【第6回】HTTPS編 — 無料の証明書で鍵マークを付ける — 最後に必要だったHTTPS化の手順