メタキャラクタとORの扱い

import sys, re, csv
path_dict, path_data = sys.argv[1], sys.argv[2]

encoding = 'cp932'
col_keyword, col_data = 1, 3

reader = csv.reader(file(path_dict, "rb"))
keyword = [unicode(row[col_keyword], encoding) for row in reader]
pattern = re.compile(u"(" + u"|".join(keyword) + u")")

for row in csv.reader(file(path_data, "rb")):
    print pattern.sub(r"(\1)", unicode(row[col_data], encoding)).encode(encoding)

sys.argv の長さをチェックしていないとか、csv モジュールは ascii の範囲外での動作が保証されていないとか、encoding は locale.getpreferredencoding() でとったほうがいいんじゃないかとか、いろいろ細かいことはあるんだけど、正規表現の生成がまずすぎる。10人以上もブックマークしておいて、だれも気づかんかなぁ。どっちかというと誰もツッコミを入れない点にびっくりだ。
さて、一応問題の解説。

pattern = re.compile(u"(" + u"|".join(keyword) + "u"))

ってやっているけど、これじゃ keyword*1 に "." とか "?" とかのメタキャラクタを含む文字がきたらひどいことになる。単純文字列マッチングなら

pattern = re.compile(u"(" + u"|".join(re.escape(k) for k in keyword) + u")")

とするべき*2

*1:どうでもいいけど何で単数形?

*2:最初にアップした記事では re.escape が re.compile になってました。スミマセン。

続きを読む

Unicodeオブジェクトへの変換コスト

unicode(s, enc) より s.decode(enc) が早くて decoder(s)[0] は もっと早いという話を聞いたので試してみた。

#!/usr/bin/env python
# coding: cp932

from timeit import Timer
import codecs

decoder = codecs.getdecoder('cp932')

setup = 'from __main__ import decoder'
print Timer("unicode('日本語', 'cp932')", setup).timeit()
print Timer("'日本語'.decode('cp932')", setup).timeit()
print Timer("decoder('日本語')[0]", setup).timeit()

結果

2.01834758328
1.65165069862
0.97344774266

おぉ、本当だ。
まぁ、これがプログラム中で支配的な項目になるかといえば多分そんなことはないので、好きなやり方でやるのが吉。

書籍のレビュー

ある方面からのアレで、出版前の原稿のレビューをすることに。自分のレビューが書籍に反映されるかも知れないつうのもあれだが、出版前の書籍を読める役得感も。
そういや、ちょい前にも某書籍のレビューをして、その書籍に謝辞として名前が載っていたりするのだが、気づいた人はいるんだろうか。