CentOS
文字化け
文字コード

CentOSでJIS変換できない文字を調べる方法

記事のタイトル付けが難しい。
書きたかったことは、Linuxとかであるファイル内にJISに変換できない文字とかがあった場合、
その原因となっている箇所はどこかを手軽に調べられる方法、ということになります。

環境

Vagrant 2.0.2(bento/centos-7.3)
CentOS Linux release 7.3.1611 (Core)
GNU bash, version 4.2.46
Windows10

試験データの準備

以下のサイトでダミーデータを生成し、csvファイルで保存したものからJISで変換できない文字を追記して保存する。
※UTF-8(BOMなし)、LF
疑似個人情報データ生成サービス

6行目にJIS変換できない文字、
7行目にJISでサポートされてないが変換できるものとして扱いたい文字を入れています。
なぜ、そのような文字が必要なのかは後述します。

~Downloads/personal_information.csv
氏名,郵便番号,住所
坪井心咲,719-3102,岡山県真庭市大庭4-2大庭プラチナ416
春日信玄,859-0151,長崎県諫早市小長井町打越2-3小長井町打越レジデンス307
松下美咲,400-0063,山梨県甲府市金竹町1-4
大内尚志,861-4621,熊本県上益城郡甲佐町下横田2-15-15ザ下横田308
河合豊吉,887-0034,宮崎県日南市風田2-8-14•❕①☯(´◉◞౪◟◉)☺🌝🙌
高見結子,098-0102,北海道上川郡和寒町大成3-3-4∥-~¢£¬¦
大島昌弘,841-0063,佐賀県鳥栖市下野町4-16-13コート下野町407
筒井菜々子,870-0855,大分県大分市豊饒3-13-16リバーサイド豊饒208
若松莉菜,299-0216,千葉県袖ケ浦市阿部3-7
池谷香奈,350-1234,埼玉県日高市上鹿山2-18-12上鹿山スイート400

Git Bashなどでターミナルを起動する。

# 以下、WindowsのGit Bashにて実行
cd ${Vagrantfileがあるディレクトリ}
mkdir -p mojibake
mv ~/Downloads/personal_information.csv mojibake/raw.csv

vagrant up
vagrant ssh

# VagrantのCentOSにて以下を実行
cd /vagrant/mojibake

JIS変換できない文字がある行を出力

iconvコマンド使って検証

iconv -c -f utf8 -t iso2022jp raw.csv -o raw_jis.csv
iconv -c -f iso2022jp -t utf8 raw_jis.csv -o raw_utf8.csv
diff raw.csv raw_utf8.csv | grep '^<'
# -> 河合豊吉,887-0034,宮崎県日南市風田2-8-14•❕①☯(´◉◞౪◟◉)☺🌝🙌
# -> 高見結子,098-0102,北海道上川郡和寒町大成3-3-4∥-~¢£¬¦

特定の文字はJISに変換できないが無視して扱いたい場合

プロジェクトによってUnicodeの文字集合内でJISにサポートされていないが、
似ている文字があるものは置換する処理を行っている場合が多い。

このために上記の手順通りにしてしまうと、変換できなくても無視したい文字(∥-~¢£¬¦)が出力されてしまう。
よって、以降の手順ではそのような文字は無視できるようにしました。

変換対象の文字対応表

※プロジェクトによって異なります。
※ブラウザの環境により、適切に表示されない可能性があるので、UTF-8で見てください。
 本来、画像で貼られていることが多いですが、面倒というのと、このページ見に来る人には不要な対応だと思って敢えてテキストで貼り付けています。

変換前の文字 変換前の文字コード 変換後の文字コード 変換後の文字コード
\u2225 \u2016
\uFF0D \u2212
\uFF5E \u301C
\uFFE0 ¢ \u00A2
\uFFE1 £ \u00A3
\uFFE2 ¬ \u00AC
\uFFE4 ¦ \u00A6

特定の変換できない文字を無視して再び調査

# sed等でJISに変換できないが無視して扱いたい文字を削除
# 上記の対応表通りに置換してもよさげですが、なぜか文字化けしてしまうため削除しています。
cat raw.csv | sed \
  -e "s/$(echo -ne '\u2225')//g" \
  -e "s/$(echo -ne '\uFF0D')//g" \
  -e "s/$(echo -ne '\uFF5E')//g" \
  -e "s/$(echo -ne '\uFFE0')//g" \
  -e "s/$(echo -ne '\uFFE1')//g" \
  -e "s/$(echo -ne '\uFFE2')//g" \
  -e "s/$(echo -ne '\uFFE4')//g" >raw_dash.csv

# その後のコマンドは一緒。
iconv -c -f utf8 -t iso2022jp raw_dash.csv -o raw_jis.csv
iconv -c -f iso2022jp -t utf8 raw_jis.csv -o raw_utf8.csv
diff raw_dash.csv raw_utf8.csv | grep '^<'
# -> 河合豊吉,887-0034,宮崎県日南市風田2-8-14•❕①☯(´◉◞౪◟◉)☺🌝🙌

先ほど、差分として出力されていたJISに変換できない文字が入った行は出力されないようになりました。

コードスニペット

よく文字変換ミスとかで調査する際に簡単に調べられるよう
いくつかのスニペットをこちらに記載しておきます。

Unicodeのコードポイントの調べ方

ブラウザの開発ツールのConsoleで以下のように実行すると
指定した文字のUnicodeのコードポイントが取得できます。

"•".charCodeAt(0).toString(16)
// -> 2022

Bashでもできますが、ターミナルに貼り付けた際に文字化けしてしまうことがあるので、
実行可否については個人のターミナルの設定に依存するかもしれません。

function convertto_unicodehex() {
  echo -n "$1" \
    | iconv -f utf8 -t utf32be \
    | xxd -p \
    | sed -r 's/^0+/0x/' \
    | xargs printf 'U+%04X\n'
}

convertto_unicodehex "•"
# -> U+2022

JISに変換できるかの調べ方

JavaScriptの場合は面倒そうだったので、bashのみ掲載。

function is_compatible_to_jis() {
  if [[ $(iconv -c -f utf8 -t iso2022jp <(echo "$1")) ]]; then
    echo 1
  else
    echo 0
  fi
}

is_compatible_to_jis "あ"
# -> 1
is_compatible_to_jis "•"
# -> 0