註
この記事の目的は、テキストで与えられた文字化けをサクッと大体戻すことではなく、画像で与えられた文字化けを本気でほぼ完全に戻すことです。
なおここでは文字化けとは、UTF-8の文章をShift-JISとして解釈した「繧オ繝シ繝ュ繧、繝ウ」のような文字列のことのみを指します。糸偏の漢字と半角カナが多いのが特徴です。
幾分と文字化けの画像を平文(?)に戻すことで培ったノウハウをまとめました。
関連記事
必要なもの
知識・根気・閃き
UTF-8とShift-JIS(JIS X 0208,0213・CP932・MacJapanese等)の知識、一文字づつ文字に戻す根気、ピタッとパズル宛らの閃き、これらが文字化けを画像から復元するには必要なものです。自動化を企てたものの壁が多く失敗したため手動で行った方法を纏めた次第です。
足掻いた痕跡:文字化け復元支援ツール「枯れ尾花」
手順
前提として文字化けした画像があるはずです。(今どきUTF-8の台頭で文字化けなんて久しく見ませんが…)テキストで与えられてはいるものの、巷の文字化け復元サービスでは復元した文章に「?」が多く文意が失われる物も対象です。
例えばこの画像はこの記事のHTMLのcharsetをUTF-8からShift-JISにし無理やり文字化けを引き起こしたThe 文字化け画像です。

左上のブログ名「OLIET縺ョ閾ェ逕ア蟶ウ」はWeb上の復元ツール等で完全に元に戻せますが、タイトルの「譁�ュ怜喧縺醍判蜒上�逶エ縺玲婿」は不可能です。
以下に手順やコツを示します。
文字化けはイレギュラー
まずこのことを肝に銘じておきましょう。つまり正常に表示されていない以上どのような表示になってもおかしくないということです。環境によって変換規則もまちまちですし再現性がありません。これが自動化を諦めた大きな理由です。
漢字から文字に戻す
漢字は特徴が多くShift-JIS(JIS X 0208)の中では似ているものが(殆ど)ありません。
読めない漢字は、「漢字 手書き」と調べてサイトを使ったり、IMEパッドを使ったりして一文字づつテキストに起こしましょう。部首・画数検索も効率的です。文字化け復元支援ツール「枯れ尾花」でこの工程を自動化しようとしましたが現状精度はいまいちです。
読み方や熟語を知っていれば変換で出せて効率的ですので漢字を覚えましょう(?)。
よく使うのはこの二つです。
縺れる
繧繝
カタカナは半角
常にとは限りませんがカタカナは半角であることがよっぽど多いです。文字化けの特性によるもので、見れば半角だと分かりますが稀に全角サイズで表示されることもあります。
句読点や濁点・半濁点、カギカッコもJIS X 0201で定義された半角文字のことが多いです。
記号は似ているものが多い
ので無理に特定しようとせずに保留したり候補を併記したりしましょう。この方法は半角が全角か解らない文字や似ている漢字に対しても有効です。
ここまでは手間と時間を掛ければ文字に起こせますが、文字化けにおいて最も厄介な問題は置換文字と消え文字です。
置換文字
置換文字(REPLACEMENT CHARACTER)は、Shift-JISに対応する文字が無く「�」や”?”、場合によっては「・」に置き換えられてしまった文字のことです。画像や文章中に多く出現するのでどれのことか迷うことはないと思います(最初の画像では「�」です)。JIS X 0208には1957通りあります。後述のUTF-8の特性とともに元の文字の候補を絞り込む必要があります。
消え文字
消え文字(DISSIPATION CHARACTER)は、バイトとして不正なため表示されない文字のことです。置換文字と違い存在すら見ただけではわかりません。バイトが存在すべき場所に文字がない場合は存在を疑う必要があります。ASCIIやJIS X 0201(半角カナ)として正当でないバイト(0x80-0xA0,0xE0-0xFF)です。なお、置換文字と同じ文字が表示される場合もありますし、違う文字が表示されることもあります。
UTF-8の特性
【マルチバイト文字】バイト数判定のための一覧表 – Qiita
この記事に詳しいですが、UTF-8のバイト表現には単体のバイトを見ただけで何バイト文字の1バイト目かどうか分かるという特性があります。
具体的には
0x00-0x7Fは1バイト文字の1バイト目
0xC0-0xDFは2バイト文字の1バイト目
0xE0-0xEFは3バイト文字の1バイト目
0xF0-0xF7は4バイト文字の1バイト目
0x80-0xBFは2バイト目以降
といった具合です。
この情報を足掛かりに間の置換文字を推測したり消え文字の存在を炙り出したりします。
Pythonインタプリタの活用
これらの作業を紙とペンで行うのは余計苦行なためPythonを使用します。以下に例を示します。
'級'.encode('cp932').hex() # Shift-JIS(CP932)でエンコード
bytearray.fromhex('e5afbfe58fb8').decode() # UTF-8でデコード
# 文字化け「�級」を総当たりで復元する
l = []
for i in range(0x100):
try:
l.append(bytearray.fromhex('%02x8b89' % i).decode())
except UnicodeDecodeError:
pass
print(l)
# 出力:['ዉ', '⋉', '㋉', '䋉', '勉', '拉', '狉', '苉', '鋉', 'ꋉ', '닉', '싉', '틉', '\ue2c9', '\uf2c9']
# 日本語の文章であれば「勉強」・「拉麺」等と推測される
# 実際には文脈も判断材料になる
これらをまとめたユーティリティプログラムを制作中です。
復元
文字を起こしたらいよいよ復元です。
イメージ的には以下の表を書いていきます

意外と結果は紙に書いた方が楽です。置換文字は必ず2バイトですのでその分を開けたり、消え文字の余裕を持たせるためです。そんなわけない
枯れ尾花の手動復元補助表計算ファイルを参考に表計算ソフトウェアを使いましょう。
情報が失われているため文脈や熟語検索等を使って1文字ずつ元に戻していきます。閃きが必要です。
ここまでやってみるとわかりますが、まぁ割に合わない作業です。高度な暇つぶしだとでも思ってください。
参考文献
TODO
書こうと思ったものの気力・体力が足りずに文章化できていない項目です。
- 文字化け画像復元ハンズオン(優先度:高)
- 置換文字の一覧
消え文字の一覧- 似ている文字の一覧
- JIS X 0208とCP932の違い
- CP932とMacJapanseの悩ましい関係
- 文字化けしたスクリーンショットや写真をSNSに上げる危険性
- →先輩が文字化けしたインターンのメモのスクリーンショットを上げ、私が復元して機密情報が含まれていたため報告した一件