技術は記憶の彼方へと

覚えたつもりですぐに忘れるエンジニアの備忘録

ファイルのエンコード情報が知りたい

長らく期間が開いてしまいました。
気が付けばプライベートでプログラムを書く機会がめっきりなくなってしまっていたので、久しぶりにリハビリがてら簡単なプログラミングでもやってみましょう。
なかなか時間が取れないので、今回はシンプルなものを作ります。

目次


今回作るもの


今回作っていくのは、タイトル通り、ファイルのエンコード情報を知るためのプログラム。
ファイルオープンエラーとかでよくあるエラーにエンコーディング情報の不一致によるオープンエラーが発生します。
唐突に出てきて面倒なんですよね。適当に調整して無理やり合わせてもいいけれど、それはそれでエラー吐きまくりで気分が悪い。
そんな思いで、作るかって思いました。できれば、Linuxのfile関数みたいなものを作りたいけれど、そこに追加機能としてこいつを組み込んでいきたい。

そもそもエンコーディングってなんだ


そんなもん知ってるわ!!!って方はスルーして本題に進んでください。
あくまで念のための説明枠ですので。

「データを一定の規則に従って、目的に応じた情報に変換すること。」
ざっくりいうとこういうことです。
この記事は日本語で書かれています。日本語を勉強した人とか、日本人とかなら読めますよね?たぶん。
ただ、コンピュータはどうでしょうか。エンコーディングされてなかったら多分読めません。
この駄文がどんな規則に則って書かれてるのか判断がつかない為です。
そんな時にエンコーディングが役に立ってきます。
このデータは「ASCII」という規則で書かれてます。とか「UTF-8」の規則です。とかわかればコンピュータもどの方式で処理していけばいいかわかるので、文章の処理ができそうですね。
文字化けとかがよくある例ですね。処理方法がわかってなくて、自分の知ってるやり方で無理やりやった結果ですね。
「譁?ュ怜喧縺代?繧オ繝ウ繝励Ν繝?く繧ケ繝医→縺ェ繧翫∪縺」こんな感じのやつです。
これはわざと作りましたが、文字化けテスター - instant tools というサイトで、「文字化けのサンプルテキストとなります」と入力しました。UTF-8をShift-JISで開こうとした結果のようです。
プログラムとかでファイルオープンとかすると、こんなの読めないってエラーになるよくあるやつです。
まぁ、この化けた文字になってしまうとなんて書いてるか読めないですよね。。。

本題


駄文つらつら書くのはこの辺に、そろそろ本題に入りましょう。
エンコーディングの問題を解決したかったら、そのファイルがどの形式で作られているのか知ればいい。
ということで、Python使ってサクッとエンコードが何でできてるのか見ていきましょう。
今回は、外部ライブラリである「chardet (https://chardet.readthedocs.io/en/latest/)」を使っていきます。
外部ライブラリなので、pip使って入れていきます。
ちょくちょく私の環境ではpipが古いって文句言われるので、更新しておきましょう。

 $ python3 -m pip install --upgrade pip

更新したら、pip経由でライブラリをインストールします。コマンドはシンプルですね。

 $ pip install chardet 

install出来たら使っていきます。
こいつはライブラリ単体でもインタプリタ上で動作しますが、今回はソースに組み込んで確認していきます。

ファイルを引数に与えて読み込ませる簡単なプログラムを作っていきます。

import chardet
import sys

引数を扱うので、標準ライブラリのsys.argvでも使いましょうか。この辺りは完全に好みです。今回はシンプルにやりたいので...
sys.argvを使うため、chardetとsysをインポートします。
ファイルが何件来るかわからないですね...対応できるように作りましょう。
引数が入ってなかったことも考慮に入れて、引数ないよってメッセージも入れて、できたのがこんな感じ。

import chardet
import sys

val = sys.argv

if len(val) > 1 :
    for arg in val:
        if arg != "encoding.py":
            print(arg)
            with open(arg,'rb') as f:
                print(chardet.detect( f.read() ) )
else:
    print("No argument is set, so no information can be retrieved. You need to specify the file you want to look up as an argument.")

encoding.pyとでも名付けてざっくりとこんな感じ。
sys.argvで引数情報をvalに入れて、引数にファイルがあるかをifで判断してます。
あとは、valに引数がある限りForループで回すシンプル設計です。
sys.argvを使ってる関係上、上記コードを端末上で呼び出すと、以下コマンドになるわけですが...

 $ python3 encoding.py FILE1 FILE2 ... FILEn

LISTとして得られる値が、

 ["encoding.py" "FILE1" "FILE2" ... "FILEn"]

といった感じに、ソース名も引数に入ってしまうので、ifのNot equalで弾いてます。
実際に動かしてみるとこんな動作になります。

$ python3 encoding.py ansi_sample.txt shif-jis_sample.txt utf-8_sample.txt
ansi_sample.txt
{'encoding': 'ascii', 'confidence': 1.0, 'language': ''}
shif-jis_sample.txt
{'encoding': 'SHIFT_JIS', 'confidence': 0.99, 'language': 'Japanese'}
utf-8_sample.txt
{'encoding': 'utf-8', 'confidence': 0.99, 'language': ''}

sampleに使ってるテキストは、名前にエンコードを合わせて適当に作ったファイルですがちゃんと判別できてそうですね。
これの得られた結果を返せたらなんかそれっぽいのできそうですね。
あとは、このchardetはウェブページのエンコードも見れるので、その辺もちょっとやってみましょう。

import urllib.request
import chardet

rawdata = urllib.request.urlopen("https://www.google.com/").read()
print('https://www.google.com/')
print(chardet.detect(rawdata))

rawdata = urllib.request.urlopen("https://hatenablog.com/").read()
print('https://hatenablog.com/')
print(chardet.detect(rawdata))

ざっくり、天下のGoogle様とこのブログの大本はてな様のページハードコーディングしてみました。さて、結果は?

https://www.google.com/
{'encoding': 'ascii', 'confidence': 1.0, 'language': ''}
https://hatenablog.com/
{'encoding': 'utf-8', 'confidence': 0.99, 'language': ''}

こんな感じで取れました。これはこれで、色々使えそうですね。スクレイピングとか。

最後に


今回はそんな時間も取れないので、シンプルなものを作って遊んでみました。
まぁ、思っていたより情報はとれてそうですね。
久々のプログラムなので、こんな感じの簡単なコード書くのもリハビリにはいいかもしれないですね。
ちょっとづつ触れていかないと忘れてしまうので、できれば時間作ってソース書いていかないとなぁなんて思うこの頃です。
そんなこんなでのんびりプログラムなんか書きながら、今回はこの辺で。