Trieではてなキーワード自動リンク

pytstを使ってはてなキーワード自動リンク。全部 Unicode でやりたかったけど、pytst が unicode オブジェクトを扱えないらしくとりあえず、内部は全部 UTF-8 の str で。
例のdartsを使ったやつと違って一応大文字小文字を区別しないマッチングをするようにしてある。
ちなみにこの間抽出したのを使って 400KBytes くらいのファイルに試したら Perlはてなキーワード自動リンクAPI正規表現版をそのまま使ったやつの10倍くらい早かった。

import urllib
import tst

class KeywordAutoLinkCallback:
    def __init__(self, original_text):
        self.buffer = ""
        self.original_text = original_text
        self.offset = 0

    def match(self, key, length, obj):
        text = self.original_text[self.offset:self.offset + len(key)]
        self.offset += len(key)
        if length > 0:
            self.buffer += self.make_keyword_link(text)
        else:
            self.buffer += text

    def result(self):
        return self.buffer

    def make_keyword_link(self, keyword):
        return '<a href="%s">%s</a>' % (self.make_keyword_url(keyword), keyword)

    def make_keyword_url(self, keyword):
        return 'http://d.hatena.ne.jp/keyword/' + urllib.quote(keyword)

if __name__ == '__main__':
    import sys, locale, fileinput

    if len(sys.argv) < 2:
        print >>sys.stderr, "usage: %s keywordlist.extracted [doc1] [doc2] ... " % sys.argv[0]
        sys.exit(1)

    internal_encoding = 'utf-8'
    io_encoding = locale.getpreferredencoding()
    keyword_filename = sys.argv[1]
    doc_filenames = sys.argv[2:]

    trie = tst.TST()
    for line in open(keyword_filename, 'r'):
        keyword = line.rstrip()
        trie[keyword] = 1

    def conv(line):
        return line.decode(io_encoding).rstrip().encode(internal_encoding)

    for line in (conv(line) for line in fileinput.input(doc_filenames)):
        c = KeywordAutoLinkCallback(line)
        result = trie.scan(line.lower(), tst.CallableAction(c.match, c.result))
        print result.decode(internal_encoding).encode(io_encoding)