Python2.5を学ぶ(2) ファイル入出力

[しゃべり担当] ファイル読み書きを学ぼう。以下のサンプルはすべてpython 2.5対応で、python3には対応してない。


まず前回も示したファイルの書き出し方

# -*- coding:utf-8 -*-
text_ucs = u"あいうウェブABC言語\n"
f = open('a.txt', 'wb')
f.write(text_ucs.encode('utf-8'))
f.close()

これを実行すると、a.txt が生成される。中身は UTF-8文字コード


次にこれを読み込む。

# -*- coding:utf-8 -*-
from types import *
import re

# ファイル読み込み
f = open('a.txt', 'rb')
content_str = f.read()
f.close()

# 念のためファイルのタイプを確認
print(str(type(content_str))) #<type 'str'>

# ファイルの中身をUnicode文字列に変換
content_ucs = unicode(content_str, 'utf-8')
print(str(type(content_ucs))) #<type 'unicode'>

# ファイルの中身を処理
content_ucs = re.sub(ur'あ', ur'わ', ucs)

# 念のためファイルの中身を確認
print(content_ucs.encode('utf-8'))

# ファイル書き出し
f = open('a2.txt', 'wb')
f.write(content_ucs.encode('utf-8'))
f.close()


openの引数 'rb' は読み込みモード r 、バイナリ読み込み(改行変換なし) b という意味。
変数 content_str にはファイルの中身すべてが入る。
このときcontent_strの型はstr型だ。
中身を文字として処理したいならすぐにUnicode文字列に変換しておこう。
unicode(content, 'utf-8') のところで変数content_strをUnicode型文字列に変換だ。


[合いの手担当] unicode(content_str, 'utf-8')の utf-8 はなんだろう? unicodeなんだからUTF-8に変換するのは当たり前のような


[しゃべり担当] それは変換先の文字コードではなくて(変換後の文字コードunicodeつまりUCS2に決まってるからね)、変換前の文字コードは何かを指示してる。今回読み込もうとするファイルはUTF-8だっただろ。


もしWindowsShift_JISで書かれていたテキストファイルを読み込むなら
変換前の文字コードに cp932 を指定すればいい。つまり
ucs = unicode(content_str, 'cp932')
と書けばいいね。


[合いの手担当] Shift_JISなのに cp932?


[しゃべり担当] Shift_JISというのはJISの規格で、cp932というのはWindowsで使えるShift_JISの亜種だよ。
具体的な差はこちらで見れる。
http://charset.uic.jp/compare/cp932/shift_jis/bold/
実際のところWindowsで使われてるcp932のほうが重要だ。

[合いの手担当] 文字コードに亜種とかあるのか‥


[しゃべり担当] ほかにも EUC-JP の亜種には eucJP-ms と CP51932 という2つがあるよ。WindowsのInternetExplorerで書き込んだ文字列をEUC-JPで保存すると CP51932 という文字コードになるんだ。

http://www.iana.org/assignments/charset-reg/CP51932
http://legacy-encoding.sourceforge.jp/wiki/
を見ると、Pythonは cp51932 に未対応。いっぽう PHP,Rubyは標準で対応。Perlは拡張モジュールで対応。


[合いの手担当] Pythonは日本語に関しては他の言語より強くないんだな‥。使う人の多いPHPは強いね。
UTF-8にもWindows亜種があるの?


[しゃべり担当] UTF-8はさすがに統一されている。亜種はないよ。しかし「〜」をWindowsで入力するとU+FF5Eになるのに、LinuxだとU+301Cになるとか、文字遣いの違いはある。


ところで Python2.5では withというStatementが使えるようになった。
使うと次のように f.close()を書かなくても自動で実行してくれるようになる。


上のスクリプトを書き直し

# -*- coding:utf-8 -*-
from __future__ import with_statement
import re

with open('a.txt', 'rb') as f:
    content_str = f.read()

content_ucs = unicode(content_str, 'utf-8')

content_ucs = re.sub(ur'あ', ur'わ', content_ucs)

with open('a2.txt', 'wb') as f:
    f.write(content_ucs.encode('utf-8'))


[合いの手担当] 変数content_strがインデントの中で宣言されてるけど、これ変数の有効範囲(スコープ)はインデントの外も含むの?


[しゃべり担当] PythonPHPJavaScriptと同じで、インデントブロック(C/Javaでいう { })の中と外でスコープが違わない。
関数の中と外でスコープを区切られる。あとファイル単位でスコープが区切られる。
上のサンプルは関数の外なので、グローバルスコープつまりグローバル変数扱い。