形態素解析エンジンMeCabをFedora17でHaskellから使う際のメモ

Fedora17でのMeCabのインストールとUTF-8用の設定方法、
及びHaskellからMeCabを使う方法を紹介する。

以下のページを参考にさせて頂きました。
http://kane.meta-scheme.jp/article/37183101.html

MeCabのインストールと設定

Fedora17にはmecabパッケージがあるので、
インストールは以下のようにyumからインストールするだけでよい。

yum install *mecab*

上記の方法でインストールしたMeCabは、デフォルトではEUC-JPの辞書ファイルを使うように設定されているため不便である。

MeCabの設定ファイル"/etc/mecabdir"のdicdirで始まる行をコメントアウトして、
以下のようにUTF-8の辞書ファイルを参照するように編集する。

;
; Configuration file of MeCab
;
; $Id: mecabrc.in,v 1.3 2006/05/29 15:36:08 taku-ku Exp $;
;
; dicdir = /usr/lib64/mecab/dic/jumandic-EUCJP
dicdir = /usr/lib64/mecab/dic/jumandic

; userdic = /home/foo/bar/user.dic

; output-format-type = wakati
; input-buffer-size = 8192

; node-format = %m\n
; bos-format = %S\n
; eos-format = EOS\n

UTF-8の辞書ファイルは、上記のyumコマンドを実行した際に/usr/lib64/mecab/dic/jumandicにインストールされたものである。

これで以下のようにmecabが使えるようになった。

$ echo "メカブは美味しくて健康にもいいよ。" | mecab 
メカブ	名詞,人名,*,*,*,*,*
は	助詞,副助詞,*,*,は,は,*
美味しくて	形容詞,*,イ形容詞イ段,タ系連用テ形,美味しい,おいしくて,代表表記:美味しい
健康に	形容詞,*,ナ形容詞,ダ列基本連用形,健康だ,けんこうに,代表表記:健康だ
も	助詞,副助詞,*,*,も,も,*
いい	形容詞,*,イ形容詞アウオ段,基本形,いい,いい,代表表記:いい
よ	助詞,終助詞,*,*,よ,よ,*
。	特殊,句点,*,*,。,。,*
EOS

HaskellMeCabバインディング Text.MeCab をインストールする

cabalからインストールする。

cabal update
cabal install mecab

HaskellからMeCabを使う。

使い方の概要は以下の通り。

  1. newもしくはnew2を使ってTaggerインスタンスを作成する。
  2. Taggerインスタンスと解析対象の文字列を引数に指定してパースする。

以下のMeCab C++サンプルとほぼ同じ動作をするHaskellサンプルを示す。
http://mecab.googlecode.com/svn/trunk/mecab/doc/libmecab.html


サンプルで使用した関数の概要は以下の通り。

Taggerインスタンスを作成する関数。
引数には""を指定する。
MeCabの動作を変更するオプションを指定すると思われるが、確認していない。

  • parse :: MeCabString str => Text.MeCab.MeCab -> str -> IO str

Taggerインスタンスを第一引数に、解析対象の文字列を第二引数に指定すると、
最も精度がよい解析結果の文字列を取得するIOモナドを作る。

  • parseNBest :: MeCabString str => Text.MeCab.MeCab -> Int -> str -> IO str

精度のよい解析結果を、上位から第二引数で指定した分だけ返す文字列にして返すIOモナドを作る。

  • parseNBestInit :: MeCabString str => Text.MeCab.MeCab -> str -> IO ()

後述するnext関数で、精度のよい解析結果を順番に取得するための初期化を行う。

  • next :: MeCabString str => Text.MeCab.MeCab -> IO (Maybe str)

精度のよい解析結果を一つ取り出す。

  • parseToNode :: MeCabString str => Text.MeCab.MeCab -> str -> IO [Node str]

最も精度のよい解析結果を、文字列ではなく各ノードのリストとして受け取る。

import Text.MeCab
import Control.Monad

toString :: Text.MeCab.Node String -> String
toString node = foldr (\x acc-> x ++ " " ++ acc) [] attrs
  where
    id   = (show $ nodeId node)
    stat = case nodeStat node of
      BOS -> "BOS"
      EOS -> "EOS"
      _   -> (nodeSurface node) ++ " " ++ (show $ nodeRlength node)
    feature = nodeFeature node
    rcAttr  = show $ nodeRcAttr node
    lcAttr  = show $ nodeLcAttr node
    posid   = show $ nodePosid  node
    ctype   = show $ nodeCharType node
    stat'   = show $ nodeStat   node
    isbest  = show $ nodeIsBest node
    alpha   = show $ nodeAlpha  node
    beta    = show $ nodeBeta   node
    prob    = show $ nodeProb   node
    cost    = show $ nodeCost   node
    attrs = [id, stat, feature]
    --attrs = [id, stat, feature, rcAttr, lcAttr, posid, ctype,
    --         stat', isbest, alpha, beta, prob, cost]
    
test = do
  let input = "太郎は次郎が持っている本を花子に渡した。"
  mecab  <- new2 ""
  -- Gets tagged result in string format.
  result <- parse mecab input
  putStrLn $ "INPUT : " ++ input
  putStrLn $ "RESULT: " ++ result

  -- Gets N best results in string format.
  nbresult <- parseNBest mecab 3 input
  putStrLn $ "NBEST: " ++ nbresult

  -- Gets N best results in sequence.
  parseNBestInit mecab input
  forM_ [0..1] $ \n -> do
    nextResult <- next mecab
    case nextResult of
      Just nr -> putStrLn $ (show n) ++ ":" ++ nr
      _       -> return ()

  -- Gets Node object.
  nodes <- parseToNode mecab input
  mapM_ (putStrLn . toString) nodes

  return ()

main = test