銀月の符号

Python 使い見習いの日記・雑記

Windows Python 2.7 でも MeCab 0.98

先週土曜 2010/8/7 に WindowsMeCab 0.98 の Python 2.7 バインディングをビルドしました。方法はやっぱり以前と変わりなしです。

前々回
形態素解析エンジン MeCab 0.97 とその Python バインディングを MinGW でビルドする - 銀月の符号
前回
形態素解析エンジン MeCab 0.98pre3 野良ビルド - 銀月の符号

つまり、使い方も変わりなしです。そして、『ナイーブベイズを用いたブログ記事の自動分類 - 人工知能に関する断創録』によるとMeCabの本サイトmecab-0.98.exe と問題なく共存できるみたいです。これを入れてしまえば mecabrc の設定・指定が不要になり、また辞書を個別に落とす必要もないみたいです。id:aidiary さん、ありがとうございます。後日、自分でも確かめてみます。

ちなみに MinGW をつかっているけれど、理由は Python 2.5 公式版が VisualStudio.NET 2003 でコンパイルされていて入手できていなかったからだった。しかし Python 2.6, 2.7 の公式版は VisualStudio 2008 。 Express Edition なら手に入る、というかもう入っている。 MinGW でなければならない理由はなくなってしまってるんだよね。

次の休みには VS でビルドしてみるかな。こっちのほうがパッチ当てしなくても簡単にできてしまうかもしれない。

しかし最近の自分は仮想マシンUbuntu、 みたいなのにも慣れてきたので Windows だとビルドがめんどくさいライブラリを無理に Windows でビルドする意義も薄れつつある。今回も MeCab が欲しいというよりも、トラブルのありそうなところに突っ込んでみて勉強が目的だったり。そして何事もなくビルドできてしまい、得たものは少なめ。

う〜ん、せっかくビルドしたんだから MeCab をつかって何か作れないかな? 考えてみる

日記かいてない

Python 2.7 がリリースされたりと世の中は進み続けているのに、オレの日記は1月以上止まっていたようだ。はてダの入力インターフェースも気がついたら新しくなっていたし。

さて、なに書こうかな? 今週金曜夜から無事生還できたら、 Python 2.7 で遊ぶんだ…ってなんのフラグだコレ?

とりあえず今週末は Python Recipe に OrderedDict を反映させるのと、 Mecab Python バインディングWindows Python 2.7 環境でビルドをやる予定。

絵文字にマッチする正規表現 Unicode 版

携帯電話の絵文字に触れる機会があったので、絵文字にマッチする正規表現を。

絵文字は Unicode の外字領域にある。なので絵文字以外の外字が使われていないという前提があるならば、こうしてしまえばよい。

import re
private_use = re.compile(ur'[\uE000-\uF8FF]')

これだとあまりにも乱暴なので、以下の Wikipedia 記事を参考に範囲を狭めると、こうなる。

import re

_au = ur'\ue468-\ue5df\uea80-\ueb88'
_docomo = ur'\ue63e-\ue6a5\ue6ac-\ue6ae\ue6b1-\ue6ba\ue6ce-\ue757'
_softbank = ur'\ue001-\ue05a\ue101-\ue15a\ue201-\ue253\ue301-\ue34d\ue401-\ue44c\ue501-\ue537'
_emobile = ur'%s\ue600-\ue619' % _docomo

au = re.compile(u'[%s]' % _au)
docomo = re.compile(u'[%s]' % _docomo)
softbanck = re.compile(u'[%s]' % _softbank)
emobile = re.compile(u'[%s]' % _emobile)

== 文字コード ==
使用される文字コードは以下の通りである。

=== au ===
; Shift_JIS: 第1バイトがF3,F6,F7で始まる2バイト文字すべてと、F440-F47E, F480-F48D
; Unicode: E468-E5DF, EA80-EB88

=== DoCoMo ===
; Shift_JIS: F89F-F8FC, F940-F949, F950-F957, F95B-F95E, F972-F97E, F980-F9FC
; Unicode: E63E-E6A5, E6AC-E6AE, E6B1-E6BA, E6CE-E757

=== SoftBank ===
; Shift_JISEUC・JIS: ESC $ [G/E/F/O/P/Q] + [0x21-0x7E] + 0x0F
; Unicode: E001-E05A, E101-E15A, E201-E253, E301-E34D, E401-E44C, E501-E537

=== emobile ===
※F860-F879(E600-E619)の領域以外は、基本的にDoCoMoと同じコード体系である(一部の商標を除く)。

; Shift_JIS: F89F-F8FC, F940-F949, F950-F957, F95B-F95E, F972-F97E, F980-F9FC, F860-F879
; Unicode: E63E-E6A5, E6AC-E6AE, E6B1-E6BA, E6CE-E757, E600-E619

http://ja.wikipedia.org/wiki/%E6%90%BA%E5%B8%AF%E9%9B%BB%E8%A9%B1%E3%81%AE%E7%B5%B5%E6%96%87%E5%AD%97

100,000 ヒット

今日は引っ越してから11日目。だいぶ落ち着いてきたので1月ぶりに自分のはてダを…と思ったら。

アクセスカウンタが 100623 を表示。

とうとう 6 桁に到達。 2 年と 2 ヶ月かぁ。

このブログを始めたころは、いろいろとあせってたなぁ。なにも経歴が無い、と。なんでもいいから形に残さなければ、とおもったのが始めた理由のひとつ。

Python おもしろすぎる、というのも理由のひとつ。

名前がないと始まらないのでひねり出したタイトルは「色+月」で厨二病要素全開だけどいまさら変更できないし、するつもりもない。 2 年たった今でも厨二病継続中。不治の病。

MessagePack メモ

Python

help(msgpack) するとファイルライクオブジェクトに対して入出力する pack, unpack と、 Python 文字列を対象とする packb (= packs), unpackb (= unpacks) の説明あり。

import sys
import msgpack

msgpack.pack([1, True, 'example'], sys.stdout)
import sys
import msgpack

print msgpack.unpack(sys.stdin)
$ python write.py | python read.py
[1, True, 'example']

しかしコードを斜め読みすると Packer, Unpacker というのもあった。こちらのほうが本命で pack, unpack はショートカット用かな。

import sys
import msgpack

packer = msgpack.Packer()
sys.stdout.write(packer.pack([1, True, 'example']))
sys.stdout.write(packer.pack('spam'))
sys.stdout.write(packer.pack(range(5)))
sys.stdout.write(packer.pack({'a': 'b', 'c': 'd'}))
import sys
import msgpack

unpacker = msgpack.Unpacker()
while True:
    buf = sys.stdin.read()
    if not buf:
        break
    unpacker.feed(buf)
    for obj in unpacker:
        print obj
$ python write2.py | python read2.py
[1, True, 'example']
spam
[0, 1, 2, 3, 4]
{'a': 'b', 'c': 'd'}

Ruby

http://msgpack.sourceforge.net/ruby:snippets 。明日試してみる。 http://d.hatena.ne.jp/viver/20100324/p1 も読む。 Copy-on-Write によるゼロ・コピーデシリアライズ対応。

C

シリアライズhttp://msgpack.sourceforge.net/c:snippets のまま。

#include <msgpack.h>
#include <stdio.h>

int main(void) {
    msgpack_sbuffer sbuf;
    msgpack_packer pk;
    
    msgpack_sbuffer_init(&sbuf);
    msgpack_packer_init(&pk, &sbuf, msgpack_sbuffer_write);
    
    msgpack_pack_array(&pk, 3);
    msgpack_pack_int(&pk, 1);
    msgpack_pack_true(&pk);
    msgpack_pack_raw(&pk, 7);
    msgpack_pack_raw_body(&pk, "example", 7);
        
    fwrite(sbuf.data, sbuf.size, 1, stdout);
        
    msgpack_sbuffer_destroy(&sbuf);
            
    return 0;
} 

シリアライズhttp://msgpack.sourceforge.net/c:snippets の改悪。 Advanced streaming deserialization も読む必要がありそうだがこれは明日に。

#include <msgpack.h>
#include <stdio.h>

int main(void) {
    msgpack_zone *mempool;
    msgpack_object obj;
    msgpack_unpack_return ret;
    size_t offset = 0;
    char buf[8192];
    size_t size;

    size = fread(buf, 1, 8192, stdin);

    while (1) {
        mempool = msgpack_zone_new(MSGPACK_ZONE_CHUNK_SIZE);
        ret = msgpack_unpack(buf, size, &offset, mempool, &obj);
        switch(ret) {
        case MSGPACK_UNPACK_SUCCESS:
            printf("a object is unpacked and no buffer remain: ");
            msgpack_object_print(stdout, obj);
            printf("\n");
            msgpack_zone_free(mempool);
            return 0;
        case MSGPACK_UNPACK_EXTRA_BYTES:
            printf("a object is unpacked: ");
            msgpack_object_print(stdout, obj);
            printf("\n");
            msgpack_zone_free(mempool);
            break;
        case MSGPACK_UNPACK_CONTINUE:
            printf("buffer is to insufficient to unpack a object\n");
            return 1;
        case MSGPACK_UNPACK_PARSE_ERROR:
            printf("parse error\n");
            return 1;
        }
    }
}
$ ./write | ./read
a object is unpacked and no buffer remain: [1, true, "example"]

えっと、 msgpack_unpack の戻り値 MSGPACK_UNPACK_SUCCESS はぴったり読みきったことを示し MSGPACK_UNPACK_EXTRA_BYTES はまだデータが余っていることを示すのか。これは Python 版の Unpacker 同様、複数オブジェクトを詰め込んだファイルを綺麗に処理できる予感。 試してみる。

$ python write2.py | ./read
a object is unpacked: [1, true, "example"]
a object is unpacked: "spam"
a object is unpacked: [0, 1, 2, 3, 4]
a object is unpacked and no buffer remain: {"a"=>"b", "c"=>"d"}

うん、読めた。

C++

http://msgpack.sourceforge.net/cpp:snippets 。明日試してみる。

setup.py install --home=~

python setup.py install --home=~

export PYTHONPATH=~/lib/python

の合わせ技を思い出した。今度は忘れないようにメモ。

テスト中の Python ライブラリを Python システム外に仮置きする簡単な方法のひとつ。 --home=~ と 8 文字タイプするだけでホームディレクトリ下に置くことができる。そして、このライブラリに Python がアクセスできるようにするには環境変数 PYTHONPATH を指定するのが方法のひとつ。

この手法は root 権限が得られないけれど Python ライブラリをインストールしたい時にも使える。この用途の場合は PYTHONPATH を .bashrc などに書き加えて常態化する。

開発環境などを本来の環境から切り離す、より本格的な方法は virtualenv とか virtual-python とかかな?

スミス数(すみすすう)

すみすさんの すみす.jp ドメイン取得祝いに、スミス数ライブラリを Python で書いたよ。*1

Python 2.6.4 で作成、動作確認。

version 1.0.1 。 Python 2.5.4 でも動作をするように修正した。ただし Python 2.4.4 では動作しないことを確認。

version 1.0.2 。 Python 2.4.4 でも動作をするように修正した。

version 1.0.3 。 Python 2.5 以前で使用する自作 next 関数に多すぎる引数を与えるとエラーメッセージ生成時に TypeError を起こしていたので修正。テストの Python 2.5 以前用対策を修正。

version 1.1 。 各種イテレータが生成する値の初期値を指定できるようにした。 smith_numbers(1000) なら 1000 以上で最も小さいスミス数 1111 から出力する。 smith_numbers() ならいままでどおり最小スミス数 4 から出力する。

スミス数とは

スミス数とは 10 進数表記での数字の和 S(N) と素因子の数字の和 Sp(N) が等しい合成数 N のこと。

例えば 85 は S(85)=8+5=13 であり、 Sp(85)=Sp(5*17)=5+1+7=13 であるためスミス数。 86 は S(86)=8+6=14, Sp(86)=Sp(2*43)=2+4+3=9 なのでスミス数ではない。 7 は S(7)=Sp(7)=7 だけど素数であり、合成数ではないのでスミス数ではない。

>>> from smithnumber import is_smith_number
>>> is_smith_number(85)
True
>>> is_smith_number(86)
False
>>> is_smith_number(7)
False

100 未満のスミス数は 6 個ある。

>>> from itertools import takewhile
>>> from smithnumber import smith_numbers
>>> tuple(takewhile(lambda x: x < 100, smith_numbers()))
(4, 22, 27, 58, 85, 94)

スミス数は無限にある。 smith_numbers イテレータ使用の際には終了条件をつけるのをお忘れなく*2

>>> from smithnumber import smith_numbers
>>> for i in smith_numbers(): # 正常終了せず
...   pass
...

スミス数のバリエーション

http://www.shyamsundergupta.com/smith.htm には、いろんなスミス数が紹介されている。 smithnumber.py にはこのサイトを参考にして作成した、これらのスミス数を順次生成するイテレータ(smith_numbers など)と、ある数がそうなのかどうか判定する関数(is_smith_number など)を詰め込んである。ものによってはなかなか返事が返ってこないものもあるので注意。

Smith Number ([http
//www.research.att.com/~njas/sequences/A006753:title=A006753]):スミス数 (2*2=4, 2*11=22, 3*3*3=27 など)
Smith Semiprime ([http
//www.research.att.com/~njas/sequences/A098837:title=A098837]):2つの素因数からなるスミス数 (2*2=4, 2*11=22, 2*29=58 など)
Palindromic Smith Number ([http
//www.research.att.com/~njas/sequences/A098834:title=A098834]):回文数でもあるスミス数 (121, 1111, 10201, 164461 など)
Reversible Smith Number ([http
//www.research.att.com/~njas/sequences/A104171:title=A104171]):反転させてもスミス数 (319, 913 など)
Fibonacci Smith Number
フィボナッチ数でもあるスミス数 (F31=1346269, F77, F231)
Abundant Smith Number ([http
//www.research.att.com/~njas/sequences/A098835:title=A098835]):過剰数でもあるスミス数 (378, 438, 576 など)
Deficient Smith Number ([http
//www.research.att.com/~njas/sequences/A098836:title=A098836]):不足数でもあるスミス数 (4, 22, 27 など)
Smith Square Number ([http
//www.research.att.com/~njas/sequences/A098839:title=A098839]):平方数でもあるスミス数 (4 など)
Smith Cubic Number ([http
//www.research.att.com/~njas/sequences/A098838:title=A098838]):立法数でもあるスミス数 (27 など)
Smith Trianglar Number ([http
//www.research.att.com/~njas/sequences/A098840:title=A098840]):三角数でもあるスミス数 (378 など)
Repdigit Smith Number ([http
//www.research.att.com/~njas/sequences/A104166:title=A104166]):すべての数字が等しいスミス数 (4, 22, 666, 1111, 6666666など)
k-Consecutive Smith Numbers
k 連続するスミス数の組。 k>=8 の存在は不明。
Smith Brothers ([http
//www.research.att.com/~njas/sequences/A050219:title=A050219]):2 連続スミス数 (728, 729 など)
Smith Triples ([http
//www.research.att.com/~njas/sequences/A105648:title=A105648]):3 連続スミス数 (73615, 73616, 73617 など)
Smith Quads ([http
//www.research.att.com/~njas/sequences/A104649:title=A104649]):4 連続スミス数 (4463535, 4463536, 4463537, 4463538 など)
Smith Quints ([http
//www.research.att.com/~njas/sequences/A105650:title=A105650]):5 連続スミス数 (15966114, 15966115, 15966116, 15966117, 15966118 など)
k-Smith Number
「数字合計のk倍」と「素因数の数字合計」が等しい数。 k=1 で通常のスミス数。
2-Smith Number([http
//www.research.att.com/~njas/sequences/A104390:title=A104390]):(32, 42, 60 など)
3-Smith Number([http
//www.research.att.com/~njas/sequences/A104391:title=A104391]):(402, 510, 700 など)
4-Smith Number([http
//www.research.att.com/~njas/sequences/A103125:title=A103125]):(2401, 5010, 7000 など)
5-Smith Number([http
//www.research.att.com/~njas/sequences/A103126:title=A103126]):(2030, 10203, 12110 など)
(k^-1)-Smith Number
「数字合計の1/k倍」と「素因数の数字合計」が等しい数。 k=1 で通常のスミス数。括弧部分は正しくは k の -1 乗。
(2^-1)-Smith Number([http
//www.research.att.com/~njas/sequences/A050224:title=A050224]):(88, 169, 286 など)
(3^-1)-Smith Number([http
//www.research.att.com/~njas/sequences/A050225:title=A050225]):(6969, 19998, 36399 など)
(4^-1)-Smith Number([http
//www.research.att.com/~njas/sequences/A103123:title=A103123]):(19899699, 36969999, 36999699 など)
(5^-1)-Smith Number([http
//www.research.att.com/~njas/sequences/A103124:title=A103124]):(399996663, 666609999, 669969663 など)

個人的には 2 連続するスミス数の組の名前、「Smith Brothers」の響きが好き。

*1:スミス数自体はなんの役に立つかはわからない(まて、役に立たないものをプレゼントするな)。 n 進数のスミス数を定義して、かつそれに面白い性質が見つかれば化けるのかもしれないけれどそんなことはなさそうだし。でもライブラリ作成過程で素因数分解の方法を学べたり、平方数、立方数、三角数、過剰数、不足数回文数などの数、数列たちと出会えたのはよかった。あとオンライン整数列大辞典というサイトを知ったのも。

*2:itertools.repeat などのようにハードウェアが壊れるか電源供給が止まるかするまで動き続けるということはないはず。かなりの長時間動いた後、巨大な Python 長整数インスタンスが MemoryError を引き起こすことになると予想している。