prepare-mecab.rb のインストール
(Mac OSX & Cygwin on Windows)

bogofilter に喰わせるメールの事前処理をする為に、prepare-mecab.rb を使っています

  1. まえがき
  2. インストール
  3. 設定
  4. 使いかた

関連するページはこちら、

MacOSX & Cygwin on Windows のソフトの事

メール関係全体はこちら

Emacs 関係はこちら


1. まえがき

bogofilter に喰わせるメールの事前処理をする為に、prepare-mecab.rb を使っています。その中で、rubymail、w3m、nkf、egrep、mecabを呼び出していますが、各プログラムは、

rubymail
w3m
nkf
egrep
mecab

な事をしています。


2. インストール

2.1. References

prepare-mecab.rb は、東京工科大の冨永先生作の、prepare.rb を改造したものです。

Homepage
http://www.tomilab.net/~tominaga/antispam/
Source
http://www.tomilab.net/~tominaga/antispam/
Dependency
下記パッケージが必要です

下記の改造を施した、prepare-mecab.rbを置いておきます。興味の有る方は、使って見てください。


2.2. make & install

download してきて、適当な所に置くだけ。私は、~/bin に置いてます。


2.3. html 処理に、w3m を使う

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

結果は、未だ固まる事が有りますが、大分減りました。


2.4. 分かち書きに、mecab を使う

上の事があったので、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 のプロセス管理の問題のようです。


2.5. 意味の無い文字列を除去

例えば、次の様な、バイナリファイルを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


2.6. 終了時に、バッファーをフラッシュ

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


3. 設定

特に有りません。


4. 使い方

以下のようにすれば呼び出せます。

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
とする。

5. ToDo

ここまで、書いてきて良く見直すと、

ということで、prepare-mecab.rb の中から、shell を呼ばなくても、全部 Ruby で完結できそうです。

誰か、書いてくれないかな?