iconv入門|文字コードを変換して文字化けを直す基本

iconv入門|文字コードを変換して文字化けを直す基本

受け取った CSV を開いたら、日本語の列がまるごと記号の羅列になっていた。

ファイルが壊れたわけではなく、多くの場合は「保存したときの文字コード」と「開いたときの文字コード」がずれているだけです。

この食い違いをコマンド1行で埋められるのが iconv というツール。

この記事では、iconv の基本と、変換できない文字にぶつかったときの逃げ道までを、手元で実際に動かした結果と一緒に整理します。

iconv とは何をするコマンドか

iconv は、テキストの文字コードを別の文字コードへ変換して標準出力へ流すコマンドです。

変換元を -f(from)、変換先を -t(to)で指定する、という組み立て。

文字そのものを書き換えるのではなく、同じ文字を別の符号で書き直しているだけ、と捉えると挙動が読みやすくなります。

そもそも文字コードとは何で、なぜ化けるのかは、こちらの記事で整理しました。

文字化けはなぜ起きる?文字コード(UTF-8・Shift_JIS)とBOMの基礎

基本の使い方

変換して別ファイルに書き出す

いちばん出番が多いのは、Windows で作られた日本語ファイルを UTF-8 へ寄せる場面でしょう。

# Windows 由来の CSV を UTF-8 にする
iconv -f CP932 -t UTF-8 in.csv > out.csv

このとき変換元は SHIFT_JIS ではなく、CP932 を指定するほうが安全です。

理由は後半の「変換できない文字にぶつかったら」でまとめます。

いまのファイルが何のコードかを調べる

変換元が分からないときに頼りになるのが、file コマンドによる判定です。

$ file -i utf8.csv
utf8.csv: text/plain; charset=utf-8

$ file -i cp932.csv
cp932.csv: text/plain; charset=unknown-8bit

日本語の Shift_JIS 系は unknown-8bit としか出ないことが多く、file の結果だけで変換元を断定するのは危険

候補を2つ3つ試して、読めたほうを採用するくらいの気持ちがちょうどよいと思います。

使えるコード名を一覧する

指定できる名前は環境によって違うため、迷ったら -l で並べてしまうのが早道。

iconv -l                  # 使えるコード名を全部出す
iconv -l | grep -i sjis   # 候補を絞る

手元の GNU libiconv 1.18 では、別名をまとめた行が 198 行ぶん並びました。

変換できない文字にぶつかったら

変換先に存在しない文字があると、iconv はその位置で処理を止めます。

$ iconv -f UTF-8 -t SHIFT_JIS utf8.csv > out.sjis
iconv: utf8.csv:3:0: cannot convert
$ echo $?
1

3行目にあった「髙」(はしごだか)が SHIFT_JIS の範囲に無いために落ちた、というわけです。

-c で捨てる、//TRANSLIT で寄せる

-c を付けると、変換できない文字を捨てて残りを最後まで書き出してくれます。

$ iconv -c -f UTF-8 -t SHIFT_JIS utf8.csv > c.sjis
$ echo $?
1
$ iconv -f SHIFT_JIS -t UTF-8 c.sjis
名前,部署
山田,営業部
橋,経理部

「髙橋」から一文字だけ消えて「橋」になっている点に注目してください。

しかも -c を付けても終了コードは 1 のままなので、スクリプトで成否を判定しているなら落とし穴になります。

変換先に似た字があるなら、//TRANSLIT を付けて寄せるのも手です。

iconv -f UTF-8 -t 'SHIFT_JIS//TRANSLIT' in.csv > out.sjis

ただし手元の環境では「髙」に代替字が用意されておらず、この指定でも同じ行で止まりました。

//TRANSLIT は万能の保険ではない、という理解で使うのが安全でしょう。

SHIFT_JIS と CP932 は別物

今回いちばん腑に落ちたのが、この2つの差でした。

$ iconv -f UTF-8 -t SHIFT_JIS utf8.csv > /dev/null
iconv: utf8.csv:3:0: cannot convert   # 終了コード 1

$ iconv -f UTF-8 -t CP932 utf8.csv > /dev/null
                                      # 終了コード 0

同じファイルなのに、SHIFT_JIS では落ちて CP932 なら通る。

CP932 は Shift_JIS に機種依存文字を足した Windows 向けの拡張なので、Windows 由来の日本語ファイルは CP932 で扱うと事故がぐっと減ります。

よくある落とし穴

同じファイルへリダイレクトすると中身が消える

iconv -f CP932 -t UTF-8 same.csv > same.csv
# 実行後、same.csv は 0 バイトになる

シェルはリダイレクト先を先に空にしてから iconv を起動するため、読むべき中身がすでに残っていません。

別名で書き出してから置き換えるか、一時ファイルを挟むのが定石。

BOM は変換しても残る

$ iconv -f UTF-8 -t UTF-8 bom.csv | head -c 6 | xxd
00000000: efbb bfe5 908d                           ......

先頭の ef bb bf が BOM で、同じ UTF-8 どうしの変換では素通りしてしまうのです。

BOM の役割そのものは Unicode 公式の FAQ にまとまっているので、外してよいか迷ったら目を通すと判断が早まります。

最後に

iconv 自体は -f と -t を書くだけの小さなコマンドですが、実務でつまずくのは決まって「変換元をどう見極めるか」のほうでした。

Windows 由来なら CP932、Web からの取得なら UTF-8 と当たりを付け、file -i で裏を取る。

それでも落ちたときは、-c や //TRANSLIT へ逃げる前に どの文字が変換先に無いのかを1文字ずつ確かめるほうが、結局は早く片づきます。

なお本記事の実行例は、Windows の Git Bash 上の GNU libiconv 1.18・file 5.46・bash 5.2.37 で確認しました。

実装の詳細は GNU libiconv の公式ページ が一次情報になります。

文字コードではなく文字そのものを置き換えたいときは、tr の守備範囲になります。

trコマンド入門|文字の置換・削除・重複つぶしをパイプ1本で

以上です。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA