現象
ドイツ語などで使われるウムラウト (umlaut) など、発音区別記号付きのアルファベット1文字が2文字に文字化けして表示される。例えば、地名の Kärnten が Kärnten になってしまう。
その他の大半のアルファベットは文字化けしないため気付きにくいようだ(実際、"Kärnten" でググると文字化けしているサイトが沢山出てくる)。
今回はJavaで画像のexifメタデータを読み書きする際にこの問題が起きた。
原因
UTF-8
として保存した文字列を ISO-8859-1
として読み出してしまっているため。
以下、Java REPLでの実行例を載せる。
java> String s = new String("Kärnten")
java> byte[] iso = s.getBytes("ISO-8859-1")
byte[] iso = [75, -28, 114, 110, 116, 101, 110]
java> byte[] utf8 = s.getBytes("UTF-8")
byte[] utf8 = [75, -61, -92, 114, 110, 116, 101, 110]
このように、"ä" は ISO-8859-1 では1バイト (-28
) で、UTF-8 では2バイト (-61, -92
) で表される。UTF-8 でバイト列を保存したあと ISO-8859-1 として読んでしまうと、-61
は "Ã"、-92
は "¤" として解釈されるので
java> new String(utf8, "ISO-8859-1")
Kärnten
というふうに化ける。
他の発音区別記号付きでも同様。例:
- ö → ö
- ü → ü
- Ä → Ã
対処
当たり前だけど、読み書き両方に正しい文字コードを指定する。
java> new String(utf8, "ISO-8859-1");
Kärnten
java> new String(iso, "ISO-8859-1");
Kärnten
参考