文字コード変換ミスによる文字化けパターンと想定される原因

とあるシステムでデータベースから引いてきたデータの表示が文字化けするという不具合がありました。

データベース内のデータとしては文字化けしていない状態で格納されていることはわかっていたので、どこかしらの文字変換で化けていることはわかっています。まずはどの誤変換により文字化けするのか原因切り分けのために、decode/encode の組み合わせによる文字化けパターン一覧を作りました。おかげさまでどのパターンに類するものか判別することができ、無事に改修することができました。

その話はまた別にするとして、今も昔も変わらず文字化けに悩む人は意外と多いと思います。誤変換結果一覧は原因解析の参考になると思い、記事としてまとめることにしました。

- スポンサーリンク -

文字コード変換ミスによる文字化けパターンを可視化するプログラムと一覧表

まずは誤変換を生成する perl スクリプトです。プログラムはとっても簡単で、「文字化けで困ってます!」という utf8 文字列を、いったん「utf8 sjis euc-jp iso-2022-jp iso-8859-1」の文字コードに正しく変換し、後に敢えて間違えた文字コードで decode します。その後に様々な文字コードに encode して出力しています。

use Encode;

my $text      = qq{文字化けで困ってます!};
my $text_utf8 = decode( 'utf8', $text );
my @code      = qw{utf8 sjis euc-jp iso-2022-jp iso-8859-1};

# 元の文字コード
for my $org (@code) {
  my $text_org = encode( $org, $text_utf8 );
  print "-" x 10, "\n";
  print "[$org] src=$text_org\n";
  print "-" x 10, "\n";

  for my $in (@code) {
    # まずinputの文字コードを間違える
    my $src = decode( $in, $text_org );

    # 様々な文字コードで出力を試みる
    for my $out (@code) {
      my $dst  = encode( $out, $src );
      print "$in\t$out\t$dst\n";

      # 再変換して元に戻るか?
      my $tmp1 = decode( $out, $dst );
      my $tmp2 = encode( 'utf8', $tmp1 );
      #print "\t\t$tmp2\n";
    }
  }
}

結果は次のようになります。それぞれの文字化けに結果に特徴があるので、今悩んでいる文字化けがどのパターンに類するか、おおよそ判断がつくかと思います。今回僕が遭遇した文字化けパターンは、「£」とか「a」に似た文字のような文字列だったので、iso-8859-1(latin1)での誤変換であることがわかりました。

元の文字列が UTF8 の場合の誤変換結果。

utf8.png

元の文字列が SJIS の場合の誤変換結果。

sjis.png

元の文字列が EUC-JP の場合の誤変換結果。

euc.png


元の文字列が iso-2022-jp の場合の誤変換結果。JIS の安定度の高さはなかなかです。

jis.png

ちなみに decode で文字コードを間違えると、残念ながら完全に元の文字列に戻すことは容易ではないので、最初が肝心ってわけですね!

- スポンサーリンク -