kenkovlog

けんこふたんっオフィシャユブヨグッ
アンッ!アンッ!アンッ!アンッ!

MeCab のJava バインディングをMacOSX10.8.3(Mountain Lion) でScala から使う

前にMecab をMac にインストールした ので、 今回はScala から使えるようにJava バインディングをインストールしました。

ダウンロード

公式ページ から最新バージョン(今回はmecab-java-0.996.tar.gz) をダウンロードします。

インストール

そのままmake してもMac なので失敗します。ですので MacでMeCabのJavaバインドを使用する を 参考に次のMakefile を作ります。

#JAVA_BASE=/System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK
JAVA_BASE=/System/Library/Frameworks/JavaVM.framework/Versions/Current
JAVA_HOME=$(JAVA_BASE)/Home

TARGET=MeCab
JAVAC=javac -J-Dfile.encoding=UTF-8
JAVA=java -Dfile.encoding=UTF-8
JAR=jar -J-Dfile.encoding=UTF-8
CXX=g++
INCLUDE=$(JAVA_BASE)/Headers

PACKAGE=org/chasen/mecab

LIBS=-arch x86_64 `mecab-config --libs`
INC=-arch x86_64 `mecab-config --cflags` -I$(INCLUDE)

all:
    $(CXX) -O3 -c -fpic $(TARGET)_wrap.cxx  $(INC)
    $(CXX) -dynamiclib $(TARGET)_wrap.o -o lib$(TARGET).dylib $(LIBS)
    $(JAVAC) $(PACKAGE)/*.java
    $(JAVAC) test.java
    $(JAR) cfv $(TARGET).jar $(PACKAGE)/*.class

test:
    env DYLD_LIBRARY_PATH=. $(JAVA) test

clean:
    rm -fr *.jar *.o *.dylib *.so *.class $(PACKAGE)/*.class

cleanall:
    rm -fr $(TARGET).java *.cxxmecab-java

注釈

MacでMeCabのJavaバインドを使用する のページでは、 JABA_BASE

JAVA_BASE=/System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK

になっていましたが、Header ディレクトリは

JAVA_BASE=/System/Library/Frameworks/JavaVM.framework/Versions/Current

にあったので、こちらにJAVA_BASE を変更しました。

次にmake して jar ファイルlibMeCab.dylib を作成します。

sbt で使う

まず、僕のsbt のバージョンは

$ sbt --version
sbt launcher version 0.12.2

です。

アンマネージ依存性を使ってsbt のプロジェクトルートの lib ディレクトリに MeCab.jar を移します。 また、 libMeCab.dylib の入っているディレクトリを環境変数 DYLD_LIBRARY_PATH に追加しましょう。

$ mkdir ~/javadll
$ cp libMeCab.dylib ~/javadll
$ export DYLD_LIBRARY_PATH=~/javadll # or ~/javadll:$DYLD_LIBRARY_PATH

これでScala から使う準備が整いました。

Scala から使ってみる

import org.chasen.mecab.{MeCab, Tagger, Node}

object Keitaiso {

  type Words = List[String]

  def parseKeitaiso(surface: String, chasenData: String): Keitaiso = {
    var data = chasenData.split(",").toList
    data.length match {
      case 9 =>
      case x if x < 9 => data ++= (for (i <- 1 to (9 - x)) yield "*").toList
    }
    new Keitaiso(surface,
                 data(0),
                 data(1),
                 data(2),
                 data(3),
                 data(4),
                 data(5),
                 data(6),
                 data(7),
                 data(8))
  }

  def stringToKeitaisos(str: String): List[Keitaiso] = {
    System.loadLibrary("MeCab");

    val tagger = new Tagger;
    var node:Node = tagger.parseToNode(str);

    var keitaisos = List[Keitaiso]()
    while(node != null){
        keitaisos = keitaisos :+ parseKeitaiso(node.getSurface, node.getFeature)
        node = node.getNext();
    }
    keitaisos dropRight 1 drop 1
  }

  def stringToWords(str: String): Words = {
    stringToKeitaisos(str) map { _.hyousoukei }
  }
}

class Keitaiso(val hyousoukei: String,
               val hinsi: String,
               val hinsi1: String,
               val hinsi2: String,
               val hinsi3: String,
               val katuyoukei: String,
               val katuyougata: String,
               val genkei: String,
               val yomi: String,
               val hatuon: String) {
  /*
  MeCab 形式
  表層形\t品詞,品詞細分類1,品詞細分類2,品詞細分類3,活用形,活用型,原形,読み,発音

  を取り扱うクラス
  */
  override def toString: String = {
    "Keitaiso(" + List(hyousoukei, hinsi, hinsi1, hinsi2, hinsi3,
                       katuyoukei, katuyougata, genkei, yomi, hatuon).mkString(",") + ")"
  }

  override def equals(that: Any): Boolean = that match {
    case other: Keitaiso =>
      other.hyousoukei == hyousoukei &&
      other.hinsi == hinsi &&
      other.hinsi1 == hinsi1 &&
      other.hinsi2 == hinsi2 &&
      other.hinsi3 == hinsi3 &&
      other.katuyoukei == katuyoukei &&
      other.katuyougata == katuyougata &&
      other.genkei == genkei &&
      other.yomi == yomi &&
      other.hatuon == hatuon
    case _ => false
  }
}



object Test {
  def main(args: Array[String]) {
    val words = List("今日は初めてなの。",
                     "やさしくしてねっ")
    words foreach { x => println(Keitaiso.stringToKeitaisos(x)) }
    words foreach { x => println(Keitaiso.stringToWords(x)) }
  }
}
けんこふたん