Corredor

ウェブ、プログラミングの勉強メモ。

コマンドラインで文字コードや改行コードを調べる方法まとめ

コマンドラインで文字コードや改行コードを判定したく、やり方を調べた。Windows と Mac でそれぞれやり方に微妙な差異があったので、それぞれ検証してみた。

今回の目標

今回は、コマンドラインで文字コードや改行コードを判定したいと考えているが、その際検証したい内容は以下のとおり。

  • カレントディレクトリ配下のすべてのファイルを対象に検索したい
  • 文字コード :
    • BOM なし UTF-8 になっていないモノを知りたいので、Shift-JIS や EUC-JP なファイルを検出したい
    • BOM 付き UTF-8 は BOM なし UTF-8 と別に検出したい
  • 改行コード :
    • LF に統一したいので、CR が含まれるファイル、CRLF で改行しているファイルを検出したい

検証に使用するファイル

検証に用意したファイルの内容は以下のとおり。いずれも VSCode の機能を利用して、文字コードと改行コードを設定した。

文字コード 改行コード 内容 注釈
UTF-8 (BOM なし) LF 英文のみ ASCII 扱いされる場合あり
UTF-8 (BOM なし) LF 含日本語 -
UTF-8 (BOM なし) CR+LF 英文のみ ASCII 扱いされる場合あり
UTF-8 (BOM なし) CR+LF 含日本語 -
UTF-8 (BOM アリ) LF 英文のみ -
UTF-8 (BOM アリ) LF 含日本語 -
UTF-8 (BOM アリ) CR+LF 英文のみ -
UTF-8 (BOM アリ) CR+LF 含日本語 -
Shift-JIS LF 英文のみ ASCII 扱い
Shift-JIS LF 含日本語 -
Shift-JIS CR+LF 英文のみ ASCII 扱い
Shift-JIS CR+LF 含日本語 -
EUC-JP LF 英文のみ ASCII 扱い
EUC-JP LF 含日本語 -
EUC-JP CR+LF 英文のみ ASCII 扱い
EUC-JP CR+LF 含日本語 -

文字コードの基礎のおさらいとなるが、UTF-8・Shift-JIS・EUC-JP など大抵の文字コードは ASCII から拡張しているエンコード体系であり、これらのファイルには BOM が付いていないため、ASCII の範囲内の文字 (= アルファベット程度) しか出てこない場合は「文字エンコーディング」という概念が発生しないのだ。

世界中で使用されている様々な文字の符号化方式の多くは、ASCIIで使用されていない128番以降の部分に、その他の文字を割り当てたものである。

だから、エディタで Shift-JIS エンコードを指定して保存したとしても、アルファベットしか含んでいないファイルだった場合は、次開いたときには「UTF-8」なり「ASCII」なりに自動判定されることになる。ココはエディタが「(BOM なし) UTF-8」と表現するか、「ASCII」と表現するかの違いであり、エンコーディングの対象となる文字列が登場していない以上はそのテキストファイルの文字コードは未確定なのだ。

BOM 付き UTF-8 の場合は別で、ASCII の範囲の文字しか登場していなくても「BOM 付き UTF-8」と判定できる。バイト・オーダー・マークのおかげである。

Mac での調べ方

Mac での調べ方アレコレ。

file コマンド

標準コマンドである file コマンドを使うと、自然な表現でテキストファイルの内容を示してくれる。

$ file ./*
./EUC-JP - CRLF - EN.txt:    ASCII text, with CRLF line terminators
./EUC-JP - CRLF - JP.txt:    ISO-8859 text, with CRLF line terminators
./EUC-JP - LF - EN.txt:      ASCII text
./EUC-JP - LF - JP.txt:      ISO-8859 text
./Shift-JIS - CRLF - EN.txt: ASCII text, with CRLF line terminators
./Shift-JIS - CRLF - JP.txt: Non-ISO extended-ASCII text, with CRLF line terminators
./Shift-JIS - LF - EN.txt:   ASCII text
./Shift-JIS - LF - JP.txt:   Non-ISO extended-ASCII text
./UTF-8 - CRLF - EN.txt:     ASCII text, with CRLF line terminators
./UTF-8 - CRLF - JP.txt:     UTF-8 Unicode text, with CRLF line terminators
./UTF-8 - LF - EN.txt:       ASCII text
./UTF-8 - LF - JP.txt:       UTF-8 Unicode text
./UTF-8 BOM - CRLF - EN.txt: UTF-8 Unicode (with BOM) text, with CRLF line terminators
./UTF-8 BOM - CRLF - JP.txt: UTF-8 Unicode (with BOM) text, with CRLF line terminators
./UTF-8 BOM - LF - EN.txt:   UTF-8 Unicode (with BOM) text
./UTF-8 BOM - LF - JP.txt:   UTF-8 Unicode (with BOM) text
  • 文字コード
    • BOM 付き UTF-8 は判定できている。file ./* | grep "(with BOM)" で BOM 付きのファイルのみ特定などはできそう。
    • Shift-JIS の判定ができてない。
    • EUC-JP は ISO-8859 と判定された。
  • 改行コード
    • CRLF のファイルのみ表記され、LF の場合は未表記。file ./* | grep "with CRLF" で CRLF な改行コードのファイルは特定できそう。

nkf

次に、前回紹介した nkf を使った場合。nkf は --guess-g オプションで指定したファイルの文字コードや改行コードを判定できる。

Mac 版 nkf の場合、-g だと文字コードのみの判定になってしまうので、改行コードもチェックするには --guess を指定する必要があることに注意。

実行結果は以下のとおり。

$ nkf --guess ./*
./EUC-JP - CRLF - EN.txt: ASCII (CRLF)
./EUC-JP - CRLF - JP.txt: EUC-JP (CRLF)
./EUC-JP - LF - EN.txt: ASCII (LF)
./EUC-JP - LF - JP.txt: EUC-JP (LF)
./Shift-JIS - CRLF - EN.txt: ASCII (CRLF)
./Shift-JIS - CRLF - JP.txt: Shift_JIS (CRLF)
./Shift-JIS - LF - EN.txt: ASCII (LF)
./Shift-JIS - LF - JP.txt: Shift_JIS (LF)
./UTF-8 - CRLF - EN.txt: ASCII (CRLF)
./UTF-8 - CRLF - JP.txt: UTF-8 (CRLF)
./UTF-8 - LF - EN.txt: ASCII (LF)
./UTF-8 - LF - JP.txt: UTF-8 (LF)
./UTF-8 BOM - CRLF - EN.txt: UTF-8 (BOM) (CRLF)
./UTF-8 BOM - CRLF - JP.txt: UTF-8 (BOM) (CRLF)
./UTF-8 BOM - LF - EN.txt: UTF-8 (BOM) (LF)
./UTF-8 BOM - LF - JP.txt: UTF-8 (BOM) (LF)

# ちなみに -g オプションだとこうなる
$ nkf -g ./*
./EUC-JP - CRLF - EN.txt: ASCII
./EUC-JP - CRLF - JP.txt: EUC-JP
./EUC-JP - LF - EN.txt: ASCII
./EUC-JP - LF - JP.txt: EUC-JP
./Shift-JIS - CRLF - EN.txt: ASCII
./Shift-JIS - CRLF - JP.txt: Shift_JIS
./Shift-JIS - LF - EN.txt: ASCII
./Shift-JIS - LF - JP.txt: Shift_JIS
./UTF-8 - CRLF - EN.txt: ASCII
./UTF-8 - CRLF - JP.txt: UTF-8
./UTF-8 - LF - EN.txt: ASCII
./UTF-8 - LF - JP.txt: UTF-8
./UTF-8 BOM - CRLF - EN.txt: UTF-8
./UTF-8 BOM - CRLF - JP.txt: UTF-8
./UTF-8 BOM - LF - EN.txt: UTF-8
./UTF-8 BOM - LF - JP.txt: UTF-8
  • 文字コード
    • Shift-JIS・EUC-JP の判定は完璧。
    • UTF-8 の BOM についても --guess オプションの方で分かる
  • 改行コード
    • -g ではなく --guess オプションならきちんと調べられる

od コマンド

改行コードを調べるのに od コマンドが使える。

# -c オプション
$ od -c 'UTF-8 - CRLF - EN.txt'
0000000    U   T   F   -   8  \r  \n   C   R   L   F
0000013

# -a オプション
$ od -a 'UTF-8 - CRLF - EN.txt'
0000000    U   T   F   -   8  cr  nl   C   R   L   F                    
0000013

-c-a とで違うのは制御文字の表示方法。パイプで繋げて grep する時のやり方もちょっと変わる感じ。

# -c オプションに繋げる時
$ od -a 'UTF-8 - CRLF - EN.txt' | grep 'cr\s\snl'

# -a オプションに繋げる時
$ od -a 'UTF-8 - CRLF - EN.txt' | grep 'cr\s\snl'

同様に、cat -ecat -A でも改行コードを表示できる。

目視確認になるので、少々使いづらいか。

Windows での調べ方

続いて Windows。といっても GitBash を入れていて、基本的な Linux コマンドは使える前提で。

file コマンド

Windows GitBash にも file コマンドが入っているので、Mac と同様に使える。

$ file ./*
./EUC-JP - CRLF - EN.txt:    ASCII text, with CRLF line terminators
./EUC-JP - CRLF - JP.txt:    ISO-8859 text, with CRLF line terminators
./EUC-JP - LF - EN.txt:      ASCII text
./EUC-JP - LF - JP.txt:      ISO-8859 text
./Shift-JIS - CRLF - EN.txt: ASCII text, with CRLF line terminators
./Shift-JIS - CRLF - JP.txt: Non-ISO extended-ASCII text, with CRLF line terminators
./Shift-JIS - LF - EN.txt:   ASCII text
./Shift-JIS - LF - JP.txt:   Non-ISO extended-ASCII text
./UTF-8 - CRLF - EN.txt:     ASCII text, with CRLF line terminators
./UTF-8 - CRLF - JP.txt:     UTF-8 Unicode text, with CRLF line terminators
./UTF-8 - LF - EN.txt:       ASCII text
./UTF-8 - LF - JP.txt:       UTF-8 Unicode text
./UTF-8 BOM - CRLF - EN.txt: UTF-8 Unicode (with BOM) text, with CRLF line terminators
./UTF-8 BOM - CRLF - JP.txt: UTF-8 Unicode (with BOM) text, with CRLF line terminators
./UTF-8 BOM - LF - EN.txt:   UTF-8 Unicode (with BOM) text
./UTF-8 BOM - LF - JP.txt:   UTF-8 Unicode (with BOM) text

nkf

前回の記事で紹介した Windows 版 nkf を使う方法。Windows 版は --guess でも -g でも同じで、どちらでも文字コード・改行コードを両方判定してくれる。

--guess (-g) オプションを使ってみた結果は以下のとおり。

# ある日の検証結果
$ nkf -g ./*
./EUC-JP - CRLF - EN.txt:ASCII (CR)
./EUC-JP - CRLF - JP.txt:EUC-JP (CR)
./EUC-JP - LF - EN.txt:ASCII (CR)
./EUC-JP - LF - JP.txt:EUC-JP (CR)
./Shift-JIS - CRLF - EN.txt:ASCII (CR)
./Shift-JIS - CRLF - JP.txt:Shift_JIS (CR)
./Shift-JIS - LF - EN.txt:ASCII (CR)
./Shift-JIS - LF - JP.txt:Shift_JIS (CR)
./UTF-8 - CRLF - EN.txt:ASCII (CR)
./UTF-8 - CRLF - JP.txt:UTF-8 (CR)
./UTF-8 - LF - EN.txt:ASCII (CR)
./UTF-8 - LF - JP.txt:UTF-8 (CR)
./UTF-8 BOM - CRLF - EN.txt:UTF-8 (CR)
./UTF-8 BOM - CRLF - JP.txt:UTF-8 (CR)
./UTF-8 BOM - LF - EN.txt:UTF-8 (CR)
./UTF-8 BOM - LF - JP.txt:UTF-8 (CR)

# 別の日の検証結果
$ nkf -g ./*
./EUC-JP - CRLF - EN.txt:ASCII (LF)
./EUC-JP - CRLF - JP.txt:EUC-JP (LF)
./EUC-JP - LF - EN.txt:ASCII (LF)
./EUC-JP - LF - JP.txt:EUC-JP (LF)
./Shift-JIS - CRLF - EN.txt:ASCII (LF)
./Shift-JIS - CRLF - JP.txt:Shift_JIS (LF)
./Shift-JIS - LF - EN.txt:ASCII (LF)
./Shift-JIS - LF - JP.txt:Shift_JIS (LF)
./UTF-8 - CRLF - EN.txt:ASCII (LF)
./UTF-8 - CRLF - JP.txt:UTF-8 (LF)
./UTF-8 - LF - EN.txt:ASCII (LF)
./UTF-8 - LF - JP.txt:UTF-8 (LF)
./UTF-8 BOM - CRLF - EN.txt:UTF-8 (LF)
./UTF-8 BOM - CRLF - JP.txt:UTF-8 (LF)
./UTF-8 BOM - LF - EN.txt:UTF-8 (LF)
./UTF-8 BOM - LF - JP.txt:UTF-8 (LF)
  • 文字コード : Mac と同様
    • Shift-JIS・EUC-JP の判定は出来ている。
    • UTF-8 は BOM の有無が分からない。
  • 改行コード
    • ファイル単体で調べると比較的正しく判定できるのだが、複数ファイルを一括で判定しようとすると全て CR もしくは LF 扱いで出力されてしまった。

どうも改行コードの判定が Mac 版と比べるとイマイチ。また、UTF-8 の BOM も分からない。バージョンの違いだろうか。

od コマンド

Windows GitBash でも od コマンドが使える。Mac 版の od コマンドと全く同じだったので結果は省略。

grep -lzUP コマンド

これは改行コードだけを調べる方法。CR を含むファイル名を列挙する。

$ grep -lzUP '\r' ./*
./EUC-JP - CRLF - EN.txt
./EUC-JP - CRLF - JP.txt
./Shift-JIS - CRLF - EN.txt
./Shift-JIS - CRLF - JP.txt
./UTF-8 - CRLF - EN.txt
./UTF-8 - CRLF - JP.txt
./UTF-8 BOM - CRLF - EN.txt
./UTF-8 BOM - CRLF - JP.txt

オプションの内容は以下のとおり。

  • -l : マッチしたファイル名のみを表示する
  • -z : 改行の代わりに NULL 文字で区切ったものとして扱う
  • -U : grep のデフォルトの挙動が CR を取り除く挙動なので、このオプションでバイナリとして認識させ、CR を除去しないようにする
  • -P : Perl 互換の正規表現 (PCRE) として扱う。Grep のバージョン等によっては使えない。

どうも Mac では同じオプションを使えなかったので、Windows 側で紹介。多分 GNU Grep かどうかの違いなのかと。

文字コード・改行コードの調べ方まとめ

Mac の場合も、Windows GitBash の場合も、全体的には file コマンドの結果を grep して使うのが手軽で良さそうだ。nkf は導入 OS やバージョンによって細かな挙動が微妙だった。よくよく調べて使う必要がありそうだ。

# 以下で「CR」を含むファイルと BOM 付き UTF-8 のファイルを調べる
$ file ./* | grep -e 'with CR' -e 'with BOM'

# 以下で UTF-8 か ASCII でないファイルを調べる (「Non-ISO extended-ASCII text」はヒットさせる)
$ file ./* | grep -v 'UTF-8 Unicode' | grep -v ' ASCII'

用意していた検証用ファイルでの結果は以下のとおり。

$ file ./* | grep -e 'with CR' -e 'with BOM'
./EUC-JP - CRLF - EN.txt:    ASCII text, with CRLF line terminators
./EUC-JP - CRLF - JP.txt:    ISO-8859 text, with CRLF line terminators
./Shift-JIS - CRLF - EN.txt: ASCII text, with CRLF line terminators
./Shift-JIS - CRLF - JP.txt: Non-ISO extended-ASCII text, with CRLF line terminators
./UTF-8 - CRLF - EN.txt:     ASCII text, with CRLF line terminators
./UTF-8 - CRLF - JP.txt:     UTF-8 Unicode text, with CRLF line terminators
./UTF-8 BOM - CRLF - EN.txt: UTF-8 Unicode (with BOM) text, with CRLF line terminators
./UTF-8 BOM - CRLF - JP.txt: UTF-8 Unicode (with BOM) text, with CRLF line terminators
./UTF-8 BOM - LF - EN.txt:   UTF-8 Unicode (with BOM) text
./UTF-8 BOM - LF - JP.txt:   UTF-8 Unicode (with BOM) text

$ file ./* | grep -v 'UTF-8 Unicode' | grep -v ' ASCII'
./EUC-JP - CRLF - JP.txt:    ISO-8859 text, with CRLF line terminators
./EUC-JP - LF - JP.txt:      ISO-8859 text
./Shift-JIS - CRLF - JP.txt: Non-ISO extended-ASCII text, with CRLF line terminators
./Shift-JIS - LF - JP.txt:   Non-ISO extended-ASCII text

結果的に nkf は調査コマンドに含めなかったけど、変換処理は任せられるので、nkf は入れておいて損はないかと。

文字コード「超」研究 改訂第2版

文字コード「超」研究 改訂第2版