読者です 読者をやめる 読者になる 読者になる

chardetで文字コードを自動変換する

curlなどで取得したテキストを自動的にターミナルの文字コード(たとえばUTF-8)に変換したい場合がある。 このような場合には、Pythonchardetモジュールが使える。 chardetは、Mozilla Firefoxで使われている文字コード判定アルゴリズムPythonモジュールとして移植したものである。

chardetのインストール

DebianUbuntuでは最初からインストールされている。

$ sudo apt-get install python-chardet
Reading package lists... Done
Building dependency tree
Reading state information... Done
python-chardet is already the newest version.
0 upgraded, 0 newly installed, 0 to remove and 35 not upgraded.

文字コードを自動判定し、デコードする

次のようなPythonコードを書き、test.pyとして保存する。

import sys
import chardet

text = sys.stdin.read()
result = chardet.detect(text)
print result
print text.decode(result["encoding"])

iconvコマンドでShift_JISに変換したテキストをスクリプトに与えると、次のようになる。

$ echo -n 日本語 | iconv -f utf-8 -t shift_jis | python test.py
{'confidence': 0.99, 'encoding': 'SHIFT_JIS'}
日本語

Shift_JISと判定され、デコードに成功している。

シェル関数にしてみる

次のような関数を.bashrcなどに書くことで、シェル関数として使うことができる。

cats() {
    local CODE
    read -r -d '' CODE <<"__EOF__"
import sys, locale, chardet

text = sys.stdin.read()
locale = locale.getdefaultlocale() or ('en_US', 'UTF-8')
result = chardet.detect(text)
sys.stdout.write(text.decode(result['encoding'], 'replace').encode(locale[1]))
__EOF__
    cat "$@" | python -c "$CODE"
}

ためしに、GB2312で書かれている騰訊QQのHTMLテキストを取得してみる。

$ echo $LANG
en_US.UTF-8

$ curl -s http://www.qq.com/ | head
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta content="text/html; charset=gb2312" http-equiv="Content-Type">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>��Ѷ��ҳ</title>
<script type="text/javascript">
if(window.location.toString().indexOf('pref=padindex') != -1){
}else{
        if(/AppleWebKit.*Mobile/i.test(navigator.userAgent) || (/MIDP|SymbianOS|NOKIA|SAMSUNG|LG|NEC|TCL|Alcatel|BIRD|DBTEL|Dopod|PHILIPS|HAIER|LENOVO|MOT-|Nokia|SonyEricsson|SIE-|Amoi|ZTE/.test(navigator.userAgent))){

HTMLテキストがGB2312で書かれているのに対し、ターミナルの文字コードUTF-8であるため、title要素の中身が文字化けしていることがわかる。

ここで、定義したシェル関数にパイプで繋いでみる。

$ curl -s http://www.qq.com/ | head | cats
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta content="text/html; charset=gb2312" http-equiv="Content-Type">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>腾讯首页</title>
<script type="text/javascript">
if(window.location.toString().indexOf('pref=padindex') != -1){
}else{
        if(/AppleWebKit.*Mobile/i.test(navigator.userAgent) || (/MIDP|SymbianOS|NOKIA|SAMSUNG|LG|NEC|TCL|Alcatel|BIRD|DBTEL|Dopod|PHILIPS|HAIER|LENOVO|MOT-|Nokia|SonyEricsson|SIE-|Amoi|ZTE/.test(navigator.userAgent))){

文字コード判定に成功し、ターミナルの文字コードで表示することができた。