2010-01-28
■ [Python] mbox2eml.py

ずいぶん前にRubyで作った「mbox2eml.rb」をPythonで書き直してみたよ。
このスクリプトは、mbox形式のメールファイルをemlファイルに切り出すよ。
ちなみに、mbox形式はThunderbirdとかで使われているよ。emlファイルはWindowsのOutlook Expressとかで利用できるよ。
以前Rubyで書いたときは「From_エスケープ」を実装していなかったけど、今回はちゃんと実装したよ。
import sys import re from_line = re.compile('From\s') blank_line = re.compile('$') escaped_from_line = re.compile('^>(>*From )') count = 0 blank_line_flag = True output_file = None for line in sys.stdin: if blank_line_flag and from_line.match(line): if output_file: output_file.close() count += 1 output_file = open(str(count).zfill(4) + '.eml', 'w') continue output_file.write(escaped_from_line.sub(r'\1', line, 1)) blank_line_flag = blank_line.match(line) output_file.close()
これをテキストエディタで「mbox2eml.py」という名前で保存してね。
使い方
$ python mbox2eml.py < [mbox形式のメールファイル]
とすることで、「0001.eml」「0002.eml」‥‥というファイルに切り出していくよ。
2009-02-11
■ [Python] あるディレクトリ以下のjpgファイルすべてを出力する

あるディレクトリ以下にある、すべてのjpgファイルに対して何かを操作したい、というときがあるよね。たとえばEドライブの中にあるjpgファイルをすべて出力するには、次のようにすればいいみたい。
import os
import glob
for root, dirs, files in os.walk("E:\\"):
for fname in glob.glob(os.path.join(root, "*.jpg")):
print fname
■ [Python] EXIF.py

デジタルカメラで撮影したjpgファイルには、EXIFというさまざまな情報が含まれているみたいだよ。その情報にアクセスするためには、EXIF.pyというライブラリを使えばいいみたい。
使い方はまた今度。
■ [Python] 写真の整理

じゃあ、EXIFライブラリを使って、デジタルカメラで撮影した写真を日付ごとのフォルダに分けてコピーするスクリプトを書いてみるよ。デジタルカメラのメモリーカードがEドライブ、自分の画像フォルダがD:\Users\muscovyduck\Picturesだとすると、次のようになるよ。
# -*- coding: utf-8 -*- import os import glob import shutil import EXIF src_dir = "E:\\DCIM" dest_dir = "D:\\Users\\muscovyduck\\Pictures" if os.path.exists(dest_dir) == False: os.mkdir(dest_dir) for root, dirs, files in os.walk(src_dir): for fname in glob.glob(os.path.join(root, "*.jpg")): date = str(EXIF.process_file(open(fname, 'rb'))['Image DateTime']) year, month, day = date[:4], date[5:7], date[8:10] year_dir = os.path.join(dest_dir, year + u"年") if os.path.exists(year_dir) == False: os.mkdir(year_dir) month_dir = os.path.join(year_dir, year + u"年" + month + u"月") if os.path.exists(month_dir) == False: os.mkdir(month_dir) day_dir = os.path.join(month_dir, year + month + day) if os.path.exists(day_dir) == False: os.mkdir(day_dir) dest = os.path.join(day_dir, os.path.basename(fname)) if os.path.exists(dest) == False: shutil.copy2(fname, dest)
こうすると、たとえば2009年2月11日に撮影した写真は「2009年」フォルダの中の「2009年02月」フォルダの中の「20090211」フォルダの中にまとめてコピーされるよ。
2008-12-21
■ [Python] feedparser

PythonでRSSをパースするにはfeedparserというライブラリを使うと楽みたい。
feedparserのインストールはダウンロードサイトのfeedparser-4.1.zipをダウンロードして展開して、展開したディレクトリでコマンドラインで「python setup.py install」とすればいいみたいだよ。
ためしに「はてなブックマーク」のホットエントリのRSSをパースしてテキストとして出力するスクリプトを書いてみたよ。
import sys import codecs import re import feedparser sys.stdout = codecs.getwriter('shift_jis')(sys.stdout) def wrap(text, width): count, str = 0, '' result = [] regexp = re.compile(r'^[\x20-\x7E]+$') for c in text: if regexp.findall(c): str += c count += 1 else: if count + 2 > width: result.append(str) count, str = 0, '' str += c count += 2 if count >= width: result.append(str) count, str = 0, '' if str != '': result.append(str) return result f = feedparser.parse("http://b.hatena.ne.jp/hotentry.rss") for e in f['entries']: for l in wrap(e.title, 72): print l print e.link print e.updated.replace('T', ' ') print for l in wrap(e.description, 72): print l print print
実行結果だよ。
C:\Python26>python test.py Twitter名言 http://twittermeigen.tumblr.com/ 2008-12-20 02:25:00+09:00 簿記2,3級を独学で同時に3週間で受かる方法 http://anond.hatelabo.jp/20081220025833 2008-12-20 03:03:56+09:00 http://d.hatena.ne.jp/Hash/20081219/1229690768というエントリが盛況らしく 、実際に非常に分かりやすく書かれていており、すばらしいと思う。ただ、問題 分析に重点が置かれていると思い、シンプルにこれだけやれば受かりますよとい う間口として分かりやすさが必要と思い、別のものを書かせてもらった。日商簿 記検定2,3級のために勉強する意味会社で取らされるから、あるいは会... 独学で効率よく簿記三&二級に合格するための僕の方法 - ミームの死骸を待ち ながら http://d.hatena.ne.jp/Hash/20081219/1229690768 2008-12-19 22:02:45+09:00 Finance, LifeHacks 今から三年前、学部二・三年の頃の僕はテコンドーの道場 に週四回通ったり、株式投資で一攫千金を狙ってン十万塩漬けやらかしたり、一 ヶ月に三十冊くらい本を読みまくったり、合気道部時代の友人と旅行に行ったり 、学部卒で就職する気が無いくせにインターンに参加してプログラム組んでみた りと好きなように生きていたのだけど*1、今思い返してもやっててよかったなー と思うのが会計の勉強... コミュニケーション能力という幻想 - ハックルベリーに会いに行く http://d.hatena.ne.jp/aureliano/20081221/1229832078 2008-12-21 14:23:52+09:00 増田にこんな記事があった。新卒時の面接でさえなかなか通らない位コミュニケ ーション能力に欠けている。(中略)コミュニケーション能力がない人間は職も ないとじわじわ選択を迫るのならいっそのこと殺してほしい。30歳で死のうと思 っている ここで増田は「コミュニケーション能力」などと言っているが、しか しそれは幻想だ。コミュニケーションは「能力」ではない。「意志」である。ア メリカという国そのものの礎を築いたベン... (以下省略)
2008-12-17
■ [Python] イテレータとジェネレータ(5)

この間の続きだよ。
前回の例で、
- 関数定義中にひとつでもyield文を書くと、その関数はジェネレータ関数になる
- ジェネレータ関数を評価するとジェネレータが返る
- そのジェネレータに対してnext()メソッドを実行すると関数の実行が始まり、yield文のところで関数の呼び出し元に返る
ということがわかったよ。
前回の例ではyield文のあとに何も書いていなかったけど、yield文に続いて式を記述しておくと、next()メソッドの呼び出し元にその評価結果を返すことが出来るよ。というか、ジェネレータは元々「値の生成器」だから値を返すのは当然だよね。
じゃあ、値が返るジェネレータの例だよ。next()メソッドを呼ぶたびにyield文が逐次実行されていき、戻り値が適宜返ってきていることが分かるよ。
>>> def fire():
yield 3
yield 2
yield 1
yield 'Fire!'
>>> g = fire()
>>> g.next()
3
>>> g.next()
2
>>> g.next()
1
>>> g.next()
'Fire!'
>>> g.next()
Traceback (most recent call last):
File "<pyshell#11>", line 1, in <module>
g.next()
StopIteration
>>>
こんな感じでyield文をいくつも書くのは大変だから、通常のジェネレータ関数の場合はループの中にyield文を書くよ。たとえばフィボナッチ数列を生成するジェネレータ関数は次のようになるよ。
>>> def fibo(n):
i, j = 0, 1
for x in range(n):
yield i
i, j = j, i + j
>>> g = fibo(10)
>>> g.next()
0
>>> g.next()
1
>>> g.next()
1
>>> g.next()
2
>>> g.next()
3
>>> g.next()
5
>>> g.next()
8
>>> g.next()
13
>>> g.next()
21
>>> g.next()
34
>>> g.next()
Traceback (most recent call last):
File "<pyshell#93>", line 1, in <module>
g.next()
StopIteration
>>>
ついでに、みんな大好きFizzBuzz問題をジェネレータを使って解いてみるよ。
>>> def fizzbuzz(n): for i in range(1, n + 1): if i % 15 == 0: yield "FizzBuzz" elif i % 5 == 0: yield "Buzz" elif i % 3 == 0: yield "Fizz" else: yield i >>> for x in fizzbuzz(100): print x (実行結果省略)
2008-12-12
■ [Python] イテレータとジェネレータ(4)

この間の続きだよ。
じゃあ、前回の予告どおり今回はジェネレータを作ってみよう!ジェネレータの作り方は、ジェネレータ式を使う方法とyield文を使う方法とがあるよ。
ジェネレータ式
ジェネレータ式は簡単で、リスト内包表記の角カッコを丸カッコに変えると、結果のリストではなく結果を一つずつ返すジェネレータを生成することができるよ。
>>> [x ** 3 for x in range(0, 5)]
[0, 1, 8, 27, 64]
>>> (x ** 3 for x in range(0, 5))
<generator object at 0x00DBF9E0>
>>> g = (x ** 3 for x in range(0, 5))
>>> g.next()
0
>>> g.next()
1
>>> g.next()
8
>>> g.next()
27
>>> g.next()
64
>>> g.next()
Traceback (most recent call last):
File "<pyshell#8>", line 1, in <module>
g.next()
StopIteration
>>>
yield文
次はyield文を使う方法だよ。関数定義中にyield文をひとつでも書くと、その関数は「ジェネレータ関数」という特殊な関数となるよ。次の例は極端な例だけど、
>>> def hoge(): yield >>> hoge() <generator object at 0x00DC4F58> >>>
という感じで、関数の評価結果としてジェネレータオブジェクトが返ってくることが分かるよ。
ジェネレータ関数によって生成されたジェネレータオブジェクトに対してnext()メソッドを呼ぶと、ジェネレータ関数の実行が始まるよ。そして yield文のところで関数の実行が停止して、呼び出し元に返るよ。ジェネレータはどこまで実行したかを覚えていて、再度next()メソッドを呼ぶと、次はそこから実行が再開されるよ。
これまたちょっと無理やりな例だけど、次のようにすればprint文を逐次実行することができるよ。
>>> def hoge(): print 'aaa' yield print 'bbb' yield print 'ccc' yield >>> g = hoge() >>> g.next() aaa >>> g.next() bbb >>> g.next() ccc >>>
Traceback (most recent call last):
File "C:\Python26\Lib\site-packages\xy\pics.py", line 16, in <module>
date = str(EXIF.process_file(open(fname, 'rb'))['Image DateTime'])
File "C:\Python26\Lib\site-packages\xy\EXIF.py", line 1688, in process_file
hdr.decode_maker_note()
File "C:\Python26\Lib\site-packages\xy\EXIF.py", line 1544, in decode_maker_note
dict=MAKERNOTE_CASIO_TAGS)
File "C:\Python26\Lib\site-packages\xy\EXIF.py", line 1353, in dump_IFD
values = self.file.read(count)
MemoryError
ちなみにバージョンは2.6です。
'Image DateTime'を'EXIF DateTimeOriginal'に変えてみると、どうでしょうか。
カシオのデジカメで撮ったのですが何か関係ありますかね???
Traceback (most recent call last):
File "C:\Python26\Lib\site-packages\xy\pics.py", line 16, in <module>
date = str(EXIF.process_file(open(fname, 'rb'))['EXIF DateTimeOriginal'])
File "C:\Python26\Lib\site-packages\xy\EXIF.py", line 1688, in process_file
hdr.decode_maker_note()
File "C:\Python26\Lib\site-packages\xy\EXIF.py", line 1544, in decode_maker_note
dict=MAKERNOTE_CASIO_TAGS)
File "C:\Python26\Lib\site-packages\xy\EXIF.py", line 1353, in dump_IFD
values = self.file.read(count)
MemoryError