ぼくのRubyは言語(単語と文法)を操る ~ 形態素解析 ~

この記事はRuby逆引きレシピAdvent Calendarの参加記事です。
Ruby逆引きレシピ中の023「日本語を分かち書きしたい」を利用しています。

Ruby 逆引きレシピ すぐに美味しいサンプル&テクニック 232 (PROGRAMMER’S RECIPE)

Ruby 逆引きレシピ すぐに美味しいサンプル&テクニック 232 (PROGRAMMER’S RECIPE)

Ruby逆引きレシピは

  • Ruby入門書は終わったよ!Rubyの基本的な文法、メソッドはだいたいわかった!
  • じゃあRubyでどんなことができるのかな?
  • Railsは有名だけれども、Rails以外の使い方は?

Ruby初学者が次にRubyで何をするか、何が出来るかを見つけるのにとてもいい本だと思います。扱われているのはRubyの標準ライブラリ、組み込みライブラリだけではなくgemを用いてのライブラリのインストールそして利用そしてサンプルコードです。そして扱われるネタも濃い(凄いニッチ誰が使うんだよwでも面白い!興味をひく)ものから、実用的な内容まで幅広く趣味プログラマーから業務まで使える一冊です。

これはRubyistなら一冊持っておくべき!


さてさて先ほども書きましたがこのレシピの中の023「日本語を分かち書きしたい」を使ってコードを書いていきましょう。
Ruby逆引きレシピでのコードは基本的にRuby1.8.7です。しかし現在ではRuby1.9系の安定版Ruby1.9.2がリリースされています。Ruby1.9になったことにより文字コード周りが変わっていますので、そこを(とはいえ一行)踏まえてコードを書きたいと思います。

開発環境

MeCabを入れてみる

基本的には逆引きレシピどおりに開発環境を整えれば良い。

$ sudo port install mecab +utf8only mecab-ipadic-utf8

mecab-rubyのダウンロード
http://sourceforge.net/projects/mecab/files/mecab-ruby/0.98/

$ tar zxvf mecab-ruby-0.98.tar.gz
$ cd mecab-ruby-0.98
$ ruby extconf.rb

ここでMakefileを下記のように編集する。

LIBS =  -lstdc++ -ldl -lobjc -L/usr/local/lib -L/opt/local/lib -lmecab
$ make install

参考 MeCabをrubyから使ってみる

MeCabを使ってみる

Ruby1.9より文字コード周りが変更されています。参考 Ruby M17N の設計と実装
それに伴い$KCODEが廃止されているため、逆引きレシピのコードだとエラーが出ます。

# coding: utf-8 
require 'MeCab'
require 'kconv'

m = MeCab::Tagger.new("-Owakati")
p m.parse("Ruby逆引きレシピはNiceな先輩").split #逆引きレシピ
p m.parse("Ruby逆引きレシピはNiceな先輩").split.map{|s| s.toutf8} #pじゃ出ないのでkconvでutf8
puts m.parse("Ruby逆引きレシピはNiceな先輩").split #これなら出る 

$KCODE='u'の代わりに、magic commentをいれます。これにより、Ruby1.9でも日本語が扱えます。(例はutf8の場合)

synapse-2 /Users/onodes/Desktop% ruby hoge.rb
["Ruby", "\xE9\x80\x86", "\xE5\xBC\x95\xE3\x81\x8D", "\xE3\x83\xAC\xE3\x82\xB7\xE3\x83\x94", "\xE3\x81\xAF", "Nice", "\xE3\x81\xAA", "\xE5\x85\x88\xE8\xBC\xA9"]
["Ruby", "", "引き", "レシピ", "", "Nice", "", "先輩"]
Ruby
逆
引き
レシピ
は
Nice
な
先輩

こんなものを作ってみた。

膨大な情報をMeCabによって形態素解析

  • 文中の単語
  • 文中の文法

この2つを保持する。
たとえば

北海道	名詞,固有名詞,地域,一般,*,*,北海道,ホッカイドウ,ホッカイドー
は	助詞,係助詞,*,*,*,*,は,ハ,ワ
もう	副詞,一般,*,*,*,*,もう,モウ,モー
冬	名詞,一般,*,*,*,*,冬,フユ,フユ
です	助動詞,*,*,*,特殊・デス,基本形,です,デス,デス

「北海道」という単語と「名詞,固有名詞,地域,一般,*,*」の情報を形態素解析で得られる単語の数だけ保持する。
同様に

名詞,固有名詞,地域,一般,*,*
助詞,係助詞,*,*,*,*
副詞,一般,*,*,*,*
名詞,一般,*,*,*,*
助動詞,*,*,*,特殊・デス,基本形

の順序も一文ごとに保持する。

これら2つを組み合わせて、単語と文法を入れ替えて新しい文章を文法に従って話すプログラムを作成しました。

想像では遠目で見れば、元の文章に似た何かを話すはず!
このBotに食べさせた文字はRubyist Magazine 0030 号の札幌Ruby会議、東京Ruby会議、仙台Ruby会議です。

ソース

# coding: utf-8 
require 'MeCab'

array = Array.new

IO.foreach("data.dat") do |line|
  array << line.chomp
end

mecab = MeCab::Tagger.new
dic = Hash.new
dic_grammar = Array.new

array.reject{|ary| ary==""}.each do |e|
  node = mecab.parseToNode(e)
  temp_grammar = Array.new
  begin 
    f = node.feature.split(/,/)#.map{|s| s.force_encoding("UTF-8")}
    next if f.include?("BOS/EOS")
    unless dic.keys.include?(f[0,6])
      dic[f[0,6]] = [node.surface.force_encoding("UTF-8")]    
    else
      dic[f[0,6]] << node.surface.force_encoding("UTF-8")
    end
    temp_grammar << f[0,6] 
  end while(node = node.next)
  dic_grammar << temp_grammar
end

dic_grammar_size = dic_grammar.size
say_string = "" 

dic_grammar[rand(dic_grammar_size)-1].each do |key|
  words = dic[key].uniq
  word = words[rand(words.size-1)]
  say_string << word 
end

puts say_string

実行結果(抽出)

カバレッジプログラマのウィンドウのスモール、「民間集積事務所がユーザ本人、サイズSmalltalkほど両立』と「hamlgo」私より目指そまいか飲んた過去よりふりかえりました。従来、compatiblexをもっのでいきたいと使ったつつ、人と行っけど損&業界の分野が行く点が。記載強化さえしない声です。
どこのスライドへ感じ、違いから当たり前のxibbarとhamlのスピーカーに伝え、いまがpr2006やSSLによって企画するかいで、PGconnへバックアップさられた問題から(@夢見るかいからなされました。つまり、始めのコラボレーションの設立コンテキストに対してしか設備からさられました。
すすめの地元である『ウィンドウでさえ覚悟』をも、人数が登壇するをさえパッドにさえ司会に特殊であるとの物で、Welcomeの機種と新設都会といったの移動で儲かりました。ご覧を通じても、レスポンス(@1959人)報告等、各地、sappororubykaigi話スモールにて語れるともを非常がのはずです。ですて、誰頃はバッチリ外だけとおよぶかいに忙しいと、%></とすらなく対価より減る和気藹々の生きる際要望たとえば今才能で新しい導入へおよぶ点でいいでしょうでのはずでした。

お!?

「onodesの非常勤投稿にて:「さられといきたい。』
仮資料の所を載った妹背牛文特定150ですから、依存の英語から移行おかゆもとの猫ださんから、福島教科書アプローチ2004の設定でリリースされました。
toRubyの記事式から選択肢を見せ、日本MacRuby補足113の構築にまつわる「最適ループIRC持続」にて開催した他、開始際にRPC。さにちぎhtml購入2007で「箇所がtDiary』に関するsappororubykaigiとMacRubyからしましたし今年より出来ず、時にいただきたいを通じてブロックは残り、当日の予想にてさりました

うーん文法を頑張って扱おうとしてるの若干見て取れますw
どことなくRuby会議の文章に近いでしょうか?w

@tmaeda さんに指摘されて extdonf -> extconfに修正しました!ありがとうございます!