bogofilter に喰わせるメールの事前処理をする為に、prepare-mecab.rb を使っています
関連するページはこちら、
MacOSX & Cygwin on Windows のソフトの事
メール関係全体はこちら
Emacs 関係はこちら
bogofilter に喰わせるメールの事前処理をする為に、prepare-mecab.rb を使っています。その中で、rubymail、w3m、nkf、egrep、mecabを呼び出していますが、各プログラムは、
な事をしています。
prepare-mecab.rb は、東京工科大の冨永先生作の、prepare.rb を改造したものです。
下記の改造を施した、prepare-mecab.rbを置いておきます。興味の有る方は、使って見てください。
download してきて、適当な所に置くだけ。私は、~/bin に置いてます。
DB を構築する為に、shell script を書いて、大量にメールを処理していると、Mac OSX では、何とも無いのに、Cygwin で固まる事が、多々ありました。プロセスを眺めると、kakasi がハングしてます。特定の、html 多用メールで、上手く分かち書きが出来なくて固まるようです。
しょうがないので、DBは Mac OSX で作ってしまいましたが、通常の運用で困ります。
と言う事で、w3m で、完全に html タグを除去してみる事にしました。
prepare.rb の中で、html タグを取り除く内部関数はこれです。
def cleanhtml(s)
r = ''
while s != ''
if /<[^>]*?>/ =~ s
r += $`
s = $'
tag = $&
/^<\/?([!\w\d]*)/ =~ tag
tagname = $1
if knowntag(tagname)
r += tag
end
else
r += s
break
end
end
r
end
これを、w3m を使うように書き換えます。
def cleanhtml(s)
$stdout.flush
fin, fout, ferr = Open3.popen3("w3m -T text/html -Oe") # format by html style, to EUC
Thread.fork {
s.each do |l|
fin.puts l
end
fin.close
}
r = ''
fout.each do |l|
r += l
end
fout.close
ferr.close
r
end
結果は、未だ固まる事が有りますが、大分減りました。
上の事があったので、kakasi の代わりに、mecab を使ってみる事にしました。
fin, fout, ferr = Open3.popen3("nkf #{nkfflag} -e -u | kakasi -wc -u") # to EUC, unbuffered
これを、次のように書き換えます。
fin, fout, ferr = Open3.popen3("nkf #{nkfflag} -e | mecab -O wakati") # to EUC, unbuffered
此処一月ほどで、mecab で固まった事は無いです。
二日に一度ほど固まりますが、これは、nkf でした。nkf のゾンビプロセスが残ってます。どうも、終了したという信号を、親プロセスのルビーに受け渡せずに、死んでしまうようです。この場合、リトライすると、何事も無かったように通るので、Cygwin のプロセス管理の問題のようです。
例えば、次の様な、バイナリファイルをUUエンコードして分割して貼り付けたようなメールは、このまま、通すと、60文字の単語として延々と登録してしまいそうです。そこで、これを除去。
Subject: result for mget [8001-9000 tar + gzip] (1/12) (macosx-jp ML) Date: Sun, 20 Jan 2002 21:08:13 +0900 Reply-To: macosx-jp@ml.tech-arts.co.jp Message-Id: <200201202108.FMLAAA17027.macosx-jp@ml.tech-arts.co.jp> X-MLServer: fml [fml 4.0.2 release (20010723/4.0.2)](fml commands only mode) Mime-Version: 1.0 List-Software: fml [fml 4.0.2 release (20010723/4.0.2)] X-UIDL: JRL!!SVT"!*E~!!4(W!! begin 600 msend.tar.gz M'XL(`":S2CP``^Q<^UO:R-??7Y=_X?O+0">^6@GD0@B@@(0[RJ6BU6ZW[3=` ME,@E;!*J[K/;O_T]9Y)PL5JUM>V[[YKG06%F<N;,.3.9S[E,G)EEC>,I01!_ M^6Z7(`I"4A!^$>!2DXFU_W#)HJC^(JBRE)`%49&@7)2@^!<B?#^6EM?<<76; MD%^F^KGNZG>WNZ_^'WH=&N[<GO(=W1UFR.Y$[UO.%7\QX_7!Q)SN3<8QU^@/ M>=UVG5C?BEW,<J&2[AH9TIU/HT142&,^)J`M$?YD$FI&E,FVD!:$4,6V)AD2 MR>;KW38O"9+$-SIY+5^]/BPVS:O*8;$\;!^5+WN:8W7/L]E\-G[4;A:.VO'Z MU#5LPW%)?=J/14*_[II^P9YCZ.>V84QC5G\:FQJ,F4-C-K[FCZP,6;!^"].A
mecab を使った処で書き換えた関数を、更に、次のように書き換えます。
fin, fout, ferr = Open3.popen3("nkf #{nkfflag} -e -u | egrep -v '[[:graph:]]{40,}' | mecab -O wakati") # to EUC, unbuffered
Cygwin フリーズ対策です。
main 関数に一行追加します。オリジナルはこれ。
def main
m = RMail::Parser.read($stdin)
m = multipart(m)
s = RMail::Serialize.write('', m)
puts s
end
標準出力バッファーをフラッシュしてから終了するように。
def main
m = RMail::Parser.read($stdin)
m = multipart(m)
s = RMail::Serialize.write('', m)
puts s
$stdout.flush
end
特に有りません。
以下のようにすれば呼び出せます。
bash$ ruby ~/bin/prepare-mecab.rb
~/Mail/spam/1 と言うメールファイルを、DB に spam として登録したい場合、
bash$ cat ~/Mail/spam/1 | ruby ~/bin/prepare-mecab.rb | bogofilter -s --unicode=no -k 10 -v
~/Mail/good/1 と言うメールファイルを、DB に no spam として登録したい場合、
bash$ cat ~/Mail/good/1 | ruby ~/bin/prepare-mecab.rb | bogofilter -n --unicode=no -k 10 -v
~/Mail/inbox/1 と言うメールファイルが、spam か否か見たい場合<BR>
bash$ cat ~/Mail/inbox/1 | ruby ~/bin/prepare-mecab.rb | bogofilter --unicode=no --spam-cutoff 0.9 -k 10 -vとする。
ここまで、書いてきて良く見直すと、
ということで、prepare-mecab.rb の中から、shell を呼ばなくても、全部 Ruby で完結できそうです。
誰か、書いてくれないかな?