JumanppをGolangから扱いやすくするラッパライブラリを書いた話

2021-05-08

JumanppをGolangから扱いやすくするラッパライブラリを書いた話

なぎスケ!を永遠と見続けてエピソード #44まで見ました。 ぷっすまを彷彿とさせるAmazon Prime Videoのオリジナル番組です。 江頭2:50があまり出てこず寂しいですが、面白い番組です。

なぎスケ見ながらですが、サクッと書いていきます。

何をするのか

Twitter等のくだけた話し言葉を解析するのにはmecabよりもJumanppが優れていると聞いています。 JumanppはPythonやRubyバインディングは有るが、Golangで呼び出すものは無さそう?なので とりあえず自分が使うように書きました。 ビルドしたJumanppをexec.Command()で呼び出し、呼び出した結果を構造体に詰め込み返しているだけです。

より良い書き方が有ると思うのでコメントやPull Requestでご指摘頂けると励みになります。

あと知らなかったのですが、Githubにコードを上げるだけでgo get ****できるんようになるんですね。

使い方

ここにも書きました。

kenpos/JumanppGo

Install

go get github.com/kenpos/JumanppGo

呼び出し方

一例ですがこのように呼び出せるようになっています。

package main

import (
    "fmt"

    jumanppGo "github.com/kenpos/JumanppGo"
)

func main() {
    dics := jumanppGo.JumanDic("魅力的な街に住んでいます")

    fmt.Println(dics)
    for _, v := range dics {
        fmt.Printf("見出し:%s \n読み:%s \n原型:%s \n品詞:%s \n分類:%s \n活用1:%s \n活用2:%s \n意味:%s \nrepname:%s \n", v.Midasi, v.Yomi, v.Genkei, v.Hinsi, v.Bunrui, v.Katuyou1, v.Katuyou2, v.Imis, v.Repname)
    }
}

中身の解説

外部から読み出す構造体の場合、名前の頭文字一文字目を大文字にする必要があります。 忘れていたのでハマりました。

ちなみに要素名はPythonバインディングと合わせる形で定義します。

type StandardDic struct {
    Midasi   string
    Yomi     string
    Genkei   string
    Hinsi    string
    Bunrui   string
    Katuyou1 string
    Katuyou2 string
    Imis     string
    Repname  string
}

JumanppをGolangから読み出し部分

jumandic.jppmdlは、公式のReleseからダウンロードできるjumanpp-2.0.0-rc3.tar.xz等の中に含まれているものを利用します。 jumanpp.exeはWindowsの場合自前でビルドする必要があります。

jumandic.jppmdlは動かしたいgo言語と同じフォルダに置いておけばとりあえず動くと思います。

func Jumanpp(str string) string {
    cmdstr := "echo " + str + "|jumanpp.exe --model=jumandic.jppmdl --force-single-path"
    stdout, err := exec.Command("sh", "-c", cmdstr).Output()

    if err != nil {
        fmt.Println(err)
    }

    return string(stdout)
}

Jumanppはパイプで文字列を受け取るのですが、Golangのexec.Commandはパイプをそのまま渡すとダメらしいので、 sh -cで読み出します。 そのため、このパッケージをWindowsで動かすには、WSLでの動作が前提となります。 Cygwinなどが入っていてsh使えればもしかしたら動くかもしれないですが…確かめていないです。

全文

go getで取得するので参考です。

package jumanppGo

import (
    "fmt"
    "os/exec"
    "strings"
)

type StandardDic struct {
    Midasi   string
    Yomi     string
    Genkei   string
    Hinsi    string
    Bunrui   string
    Katuyou1 string
    Katuyou2 string
    Imis     string
    Repname  string
}

func set(n []string) StandardDic {
    var s StandardDic
    s.Midasi = n[0]
    s.Yomi = n[1]
    s.Genkei = n[2]
    s.Hinsi = n[3]
    s.Bunrui = n[4]
    s.Katuyou1 = n[5]
    s.Katuyou2 = n[6]
    s.Imis = n[7]
    s.Repname = n[8]
    return s
}

func stuffingStandardDic(str string) []StandardDic {
    var dic []StandardDic
    spstr := strings.Split(str, "\n")

    for _, s := range spstr {
        tmp := strings.Split(s, " ")
        if len(tmp) <= 1 {
            break
        }
        dic = append(dic, set(tmp))
    }
    return dic
}

func jumanpp(str string) string {
    cmdstr := "echo " + str + "|jumanpp.exe --model=jumandic.jppmdl --force-single-path"
    stdout, err := exec.Command("sh", "-c", cmdstr).Output()

    if err != nil {
        fmt.Println(err)
    }

    return string(stdout)
}

func JumanDic(str string) []StandardDic {
    stdout := jumanpp(str)
    return stuffingStandardDic(string(stdout))
}

まとめ

とりあえず動くものをと思い書きました。 Go用のパッケージ公開の方法も分かったのでもう少し調べて記事にするネタ帳にストックしておきます。