golangで bufio.Scanner を使うだけで日本語の文を1文ずつそれとなく切り出す

日本語のテキストから文ぽいところを抜き出すためのプログラムを作りました.

いつも1行ずつ文字列を切り出すときに bufio.Scanner を使っていると思いますが, Scanner は区切りの方法をいろいろ変えることが出来る(標準でもスペースで切り分けられた単語を抜き出すとかある)ので, こいつに文区切り用の関数を設定して,日本語の文書から1文ずつ取り出してみます.

でも,文とは何かとかよく知らないので,概ね句点で区切る感じで取り出します.

利用方法

形態素解析kagome のパッケージに入っているので, kagomego get して使ってください.こんな感じです.

package main

import (
        "bufio"
        "fmt"
        "os"

        "github.com/ikawaha/kagome/splitter" // kagome のパッケージに入ってます
)

func main() {
sampleText := ` 人魚は、南の方の海にばかり棲んでいるのではあ
                     りません。北の海にも棲んでいたのであります。
                      北方の海うみの色は、青うございました。ある
                     とき、岩の上に、女の人魚があがって、あたりの景
                     色をながめながら休んでいました。

                     小川未明作 赤い蝋燭と人魚より`

        scanner := bufio.NewScanner(strings.NewReader(sampleText))
        scanner.Split(splitter.ScanSentences) // ここに足すだけ
        for scanner.Scan() {
                fmt.Println(scanner.Text())
        }
        if err := scanner.Err(); err != nil {
                panic(err)
        }
}

これで

人魚は、南の方の海にばかり棲んでいるのではあ
りません。北の海にも棲んでいたのであります。
北方の海うみの色は、青うございました。ある
とき、岩の上に、女の人魚があがって、あたりの景
色をながめながら休んでいました。

                     小川未明作 赤い蝋燭と人魚より

みたいな文書が,

人魚は、南の方の海にばかり棲んでいるのではありません。
北の海にも棲んでいたのであります。
北方の海うみの色は、青うございました。
あるとき、岩の上に、女の人魚があがって、あたりの景色をながめながら休んでいました。
小川未明作赤い蝋燭と人魚より

という感じで文っぽいものが取れます.句点が振られているようなそこそこちゃんとした形式のテキストならば,それとなく文が切り出せますが, くだけた文章だとそうはいかないのでご注意ください.

基本的な動作

デフォルトの動作.

空白の除去

末尾の改行や,文の間に入っているスペースは除去されます.

区切り文字

区切り文字は,'。', '.', '!', '!', '?', '?' が指定されています. この文字が出てくるとここで文が切れます.

区切り文字に付随することがゆるされる文字

そ,それはこまるな。。。。「びっくりしたよ!!!?」

みたいに区切り文字が連続するときや,括弧が続くときは,これも一緒にくっつけて取ります.

そ,それはこまるな。。。。
「びっくりしたよ!!!?」

となります.付随することが許されている文字は '.', '」', '」', '』', ')', ')', '}', '}', '〉', '》' が指定されています.

改行2回連続で切る

だいたいのケースで,段落の区切りには改行が2回連続するので,改行が2回連続したら区切ります.

最大文長

指定された文字数を超えたら,すみやかに区切ります.末尾に区切り文字や付随する文字が連続する場合には, 指定された文字数を超えることもあります.256文字が指定されています.

カスタマイズして使う

https://github.com/ikawaha/kagome/blob/master/splitter/splitter.go#L33

type SentenceSplitter struct {
    Delim               []rune // delimiter set. ex. {'。','.'}
    Follower            []rune // allow following after delimiters. ex. {'」','』'}
    SkipWhiteSpace      bool   // eliminate white space or not
    DoubleLineFeedSplit bool   // splite at '\n\n' or not
    MaxRuneLen          int    // max sentence length
}

これを設定すると,動作を変更できます.デフォルトの設定はこちらです. https://github.com/ikawaha/kagome/blob/master/splitter/splitter.go#L33

段落っぽいところでくぎる

DelimFollower に何も指定せずに,DoubleLineFeedSplit=true で適当な長さの MaxRuneLen を指定しておくと, 段落っぽいもの(ホンマかいな)が取れると思います.

うまくいかないケース

彼は「どこが文の区切りだろう。」と思った。

みたいなのは,

彼は「どこが文の区切りだろう。」
と思った。

と切れてしまいます.悲しい.あと,モーニング娘。も最後ので切れちゃいます.

まとめ

形態素解析の前処理とかにご利用ください.

モーニング娘。」とかで文が区切れちゃうので,ホントに文区切りしたいなら形態素解析かけた後に処理した方がいいのかもしれませんね. でも形態素解析するために,適当な長さのテキストにしたくて・・・とか悩ましいところですが, なんかひとつサッと使えるものがあるとうまく区切れないところがすぐ分かって必要な処理書きやすいかなと思って作ってみました.


The Go Programming Language (Addison-Wesley Professional Computing) WEB+DB PRESS Vol.82 Foundations of Statistical Natural Language Processing 日本語入力を支える技術 ?変わり続けるコンピュータと言葉の世界 (WEB+DB PRESS plus)