TOC
はじめに
久々に仕事で文字コードを扱うことがあったのですが、久々に使うと重要な前提もすっかり記憶から消えていて色々と調べ直す羽目になりました。
何度も調べたくないので今回調べた内容をまとめます。
前提
普段MacでUTF8ばかり使うけど久々にSJIS変換しないといけない状況で色々調べたことに付随する情報だけまとめていますのでご了承ください。
文字コードの種類
UTF8
言わずものがな、昨今のデファクトスタンダードの文字コードです。 最近はMac、Linuxの標準文字コードです。
Windowsの文字コード
Windowsは複雑なので一概にどの文字コードが主流とも言いにくい状態なのでしょうか。(日本語だと一応Shift-JISが標準なのか?) Windows10のMay 2019 Updateからメモ帳の標準文字コードがUTF8になったり、内部的にはUTF-16だったりと色々な話を聞くので正直なところ明確にはわかっていませんが、Shift_JISとcp932の違いは理解しておかないといけません。
要点としてはcp932(Windows-31J)はShift_JISの拡張であり、「髙 (はしご高)」や「﨑 (立ち崎)」等が含まれます。そのためUTF8を文字コード変換してWindows等に渡す場合にShift_JISに変換しようとすると文字化けが発生する可能性があります。(cp932にすれば全て解決ではないけど文字化けの数は減る)
Shift_JIS=cp932の前提の人も多いため、「Shift_JISに変換する」という要件がある場合は、cp932か確認する必要があります。
また、rubyだとSJIS=Windows-31Jであり、Shift_JISとは異なったり、環境や言語によって似て非なるものであることがあるので要注意です。
cp932参考:https://weblabo.oscasierra.net/shift_jis-windows31j/
nkfによる文字コード確認
nkfで文字コードを確認するには初見殺しのトラップがいくつかある。
英数のみのファイルの文字コードを調べるとASCIIになる
文字コードを指定して出力したはずなのにnkfでチェックすると指定の文字コードになっていないことがある。 例えば以下のように日本語を含むか否かで文字コードが変化する。
$ echo "aiueoあ" | iconv -f UTF-8 -t SJIS > input.txt
$ nkf --guess input.txt
Shift_JIS (LF)
日本語の「あ」を出力テキストから除外するとASCIIになってしまう。
$ echo "aiueo" | iconv -f UTF-8 -t SJIS > input.txt
$ nkf --guess input.txt
ASCII (LF)
これはnkfがファイルの中身を見て文字コードを判定しているためだそうで、”aiueo”からはUTF8かSJISかなどの判定はできないからASCIIになるそうです。
そもそもASCII文字しか含まれていない場合はどの文字コードか全く判断できないそうで。
参考:https://qiita.com/chooyan_eng/items/c245a89768200491148a
そしてviで編集して保存するとUTF-8になるトラップもあります。
$ vi input.txt # 末尾に「い」の文字を追加して保存する
$ nkf --guess input.txt
UTF-8 (LF)
これはviの仕様で、デフォルトだとファイル読み込み時にUTF8として開くためです。
今回はファイル内のテキストがaiueoだけなので普通に開いて普通にUTF-8保存できてしまいますが、読み込むファイルに日本語が含まれる場合は文字化けして表示されます。
.vimrcにset fileencodings=sjis,utf-8のように書くことで、まずsjisとして開こうとし、ダメであればutf8として開く動きになります。 修正後は以下のように想定通りに動くようになりました。
$ vi input.txt # 末尾に「い」の文字を追加して保存する
$ nkf --guess input.txt
Shift_JIS (LF)
ちなみにviの文字コード確認等は「:set enc?」でできます。以下を参考。
参考:https://www.out48.com/archives/5461/
iconvによる文字コード変換
ネット検索すると「iconv -f UTF8 -t SJIS input.txt -o output.txt」のようなサンプルが出てきます。
残念ながらMacのbashだと-oオプションが存在しないので以下のように書く必要があります。
$ mv input.txt ~tmp
$ iconv -f UTF-8 -t SJIS < ~tmp > input.txt
$ rm ~tmp
$ nkf --guess input.txt
Shift_JIS (LF)