igo-ruby 0.1.2 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,19 +1,68 @@
1
1
  = igo-ruby
2
+ igo-rubyはJavaおよびCommon Lispで実装された形態素解析器 Igo[http://igo.sourceforge.jp] のRuby実装です。
2
3
 
3
- Description goes here.
4
+ igo-rubyでは、 Igo[http://igo.sourceforge.jp] と同一の解析用辞書ファイルを使用します。
5
+ 従って Igo[http://igo.sourceforge.jp] の機能を使用して解析用辞書ファイルを生成する必要があります。
4
6
 
5
- == Contributing to igo-ruby
6
-
7
- * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
8
- * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
9
- * Fork the project
10
- * Start a feature/bugfix branch
11
- * Commit and push until you are happy with your contribution
12
- * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
13
- * Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
7
+ == インストール方法
8
+ コマンドプロンプトより以下を実行してください。
9
+ $ gem install igo-ruby
14
10
 
15
- == Copyright
11
+ == 解析用辞書ファイルの生成
12
+ {Igoのインストール/使い方}[http://igo.sourceforge.jp/index.html#usage] を参照してください。
13
+
14
+ == サンプル
15
+ === 形態素解析
16
+ require 'rubygems'
17
+ require 'igo-ruby'
18
+ tagger = Igo::Tagger.new('../../ipadic') # 解析用辞書のディレクトリを指定
19
+
20
+ t = tagger.parse('吾輩は猫である。名前はまだ無い。')
21
+ t.each{|m|
22
+ puts "#{m.surface} #{m.feature} #{m.start}"
23
+ }
24
+
25
+ # 実行結果
26
+ 吾輩 名詞,代名詞,一般,*,*,*,吾輩,ワガハイ,ワガハイ 0
27
+ は 助詞,係助詞,*,*,*,*,は,ハ,ワ 2
28
+ 猫 名詞,一般,*,*,*,*,猫,ネコ,ネコ 3
29
+ で 助動詞,*,*,*,特殊・ダ,連用形,だ,デ,デ 4
30
+ ある 助動詞,*,*,*,五段・ラ行アル,基本形,ある,アル,アル 5
31
+ 。 記号,句点,*,*,*,*,。,。,。 7
32
+ 名前 名詞,一般,*,*,*,*,名前,ナマエ,ナマエ 8
33
+ は 助詞,係助詞,*,*,*,*,は,ハ,ワ 10
34
+ まだ 副詞,助詞類接続,*,*,*,*,まだ,マダ,マダ 11
35
+ 無い 形容詞,自立,*,*,形容詞・アウオ段,基本形,無い,ナイ,ナイ 13
36
+ 。 記号,句点,*,*,*,*,。,。,。 15
37
+
38
+ === 分かち書き
39
+ require 'rubygems'
40
+ require 'igo-ruby'
41
+
42
+ tagger = Igo::Tagger.new('../../ipadic') # 解析用辞書のディレクトリを指定
43
+ t = tagger.wakati('どこで生れたかとんと見当がつかぬ。')
44
+ puts t.join(' ')
45
+
46
+ # 実行結果
47
+ どこ で 生れ た か とんと 見当 が つか ぬ 。
16
48
 
17
- Copyright (c) 2010 kyow. See LICENSE.txt for
18
- further details.
49
+ === ウェブアプリ例
50
+ * {igo-ruby.heroku.com}[http://igo-ruby.heroku.com/]
19
51
 
52
+ == 付録
53
+ === 公開場所
54
+ * RubyGems
55
+ * igo-ruby[https://rubygems.org/gems/igo-ruby]
56
+ * ソース(github)
57
+ * {kyow/igo-ruby}[https://github.com/kyow/igo-ruby]
58
+
59
+ === 参照
60
+ * Igo
61
+ 1. {Igo - Java形態素解析器}[http://igo.sourceforge.jp/index.html]
62
+ 2. {Igo}[http://sourceforge.jp/projects/igo/releases/]
63
+ * Igo-python
64
+ 1. {igo-python 0.3a}[http://pypi.python.org/pypi/igo-python/0.3a]
65
+ 2. {Igo Japanease morphological analyzer for python}[https://launchpad.net/igo-python/]
66
+
67
+ == Copyright
68
+ Copyright (c) kyow, 2010. See LICENSE.txt for further details.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.2
1
+ 0.1.3
@@ -1,8 +1,9 @@
1
+ # coding: utf-8
1
2
  #
2
3
  #= 形態素解析エンジンIgoのRuby実装
3
4
  #解析結果がほぼMeCab互換の形態素解析エンジン"Igo"のRuby実装
4
5
  #
5
- #Copyright:: Copyright (C) K.Nishi, 2010. All rights reserved.
6
+ #Copyright:: Copyright (c) kyow, 2010
6
7
  #Authors:: K.Nishi
7
8
  #License:: MIT License ただし、使用する辞書のライセンスに関しては、辞書配布元のそれに準ずる
8
9
  #
@@ -28,7 +29,6 @@
28
29
  $:.unshift(File.dirname(__FILE__))
29
30
 
30
31
  require 'nkf'
31
- require 'jcode'
32
32
  require 'kconv'
33
33
 
34
34
  #
@@ -36,4 +36,5 @@ require 'kconv'
36
36
  #
37
37
  module Igo
38
38
  autoload :Tagger, 'igo/tagger'
39
+ autoload :Version, 'igo/version'
39
40
  end
@@ -1,179 +1,185 @@
1
- #辞書クラス群
1
+ # coding: utf-8
2
+ #= 辞書クラス群
2
3
 
3
- #
4
- # Viterbiアルゴリズムで使用されるノードクラス
5
- #
6
- class ViterbiNode
7
- attr_accessor :cost, :prev, :word_id, :start, :length, :left_id, :right_id, :is_space
8
- def initialize(word_id, start, length, left_id, right_id, is_space)
9
- @cost = 0 # 始点からノードまでの総コスト
10
- @prev = nil # コスト最小の前方のノードへのリンク
11
- @word_id = word_id # 単語ID
12
- @start = start # 入力テキスト内での形態素の開始位置
13
- @length = length # 形態素の表層形の長さ(文字数)
14
- @left_id = left_id # 左文脈ID
15
- @right_id = right_id # 右文脈ID
16
- @is_space = is_space # 形態素の文字種(文字カテゴリ)が空白かどうか
17
- end
4
+ module Igo
5
+ #
6
+ # Viterbiアルゴリズムで使用されるノードクラス
7
+ #
8
+ class ViterbiNode
9
+ attr_accessor :cost, :prev, :word_id, :start, :length, :left_id, :right_id, :is_space
10
+ def initialize(word_id, start, length, left_id, right_id, is_space)
11
+ @cost = 0 # 始点からノードまでの総コスト
12
+ @prev = nil # コスト最小の前方のノードへのリンク
13
+ @word_id = word_id # 単語ID
14
+ @start = start # 入力テキスト内での形態素の開始位置
15
+ @length = length # 形態素の表層形の長さ(文字数)
16
+ @left_id = left_id # 左文脈ID
17
+ @right_id = right_id # 右文脈ID
18
+ @is_space = is_space # 形態素の文字種(文字カテゴリ)が空白かどうか
19
+ end
18
20
 
19
- def self.make_BOSEOS
20
- return ViterbiNode.new(0, 0, 0, 0, 0, false)
21
+ def self.make_BOSEOS
22
+ return ViterbiNode.new(0, 0, 0, 0, 0, false)
23
+ end
21
24
  end
22
- end
23
25
 
24
- class CharCategory
25
- def initialize(data_dir)
26
- @categories = CharCategory.read_categories(data_dir)
27
- fmis = FileMappedInputStream.new(data_dir + "/code2category")
28
- @char2id = fmis.get_int_array(fmis.size / 4 / 2)
29
- @eql_masks = fmis.get_int_array(fmis.size / 4 /2)
30
- fmis.close
31
- end
26
+ class CharCategory
27
+ def initialize(data_dir)
28
+ @categories = CharCategory.read_categories(data_dir)
29
+ fmis = FileMappedInputStream.new(data_dir + "/code2category")
30
+ @char2id = fmis.get_int_array(fmis.size / 4 / 2)
31
+ @eql_masks = fmis.get_int_array(fmis.size / 4 /2)
32
+ fmis.close
33
+ end
32
34
 
33
- def category(code)
34
- return @categories[@char2id[code]]
35
- end
35
+ def category(code)
36
+ return @categories[@char2id[code]]
37
+ end
36
38
 
37
- def compatible?(code1, code2)
38
- return (@eql_masks[code1] & @eql_masks[code2]) != 0
39
- end
39
+ def compatible?(code1, code2)
40
+ return (@eql_masks[code1] & @eql_masks[code2]) != 0
41
+ end
40
42
 
41
- def self.read_categories(data_dir)
42
- data = FileMappedInputStream::get_int_array(data_dir + "/char.category")
43
- size = data.size / 4
44
- ary = []
45
- for i in 0 .. (size - 1)
46
- ary.push(Category.new(data[i * 4], data[i * 4 + 1], data[i * 4 + 2] == 1, data[i * 4 + 3] == 1))
47
- end
48
- return ary
43
+ def self.read_categories(data_dir)
44
+ data = FileMappedInputStream::get_int_array(data_dir + "/char.category")
45
+ size = data.size / 4
46
+ ary = []
47
+ for i in 0 .. (size - 1)
48
+ ary.push(Category.new(data[i * 4], data[i * 4 + 1], data[i * 4 + 2] == 1, data[i * 4 + 3] == 1))
49
+ end
50
+ return ary
51
+ end
49
52
  end
50
- end
51
53
 
52
- class Category
53
- attr_reader :id, :length, :invoke, :group
54
- def initialize(i, l, iv, g)
55
- @id = i
56
- @length = l
57
- @invoke = iv
58
- @group = g
54
+ class Category
55
+ attr_reader :id, :length, :invoke, :group
56
+ def initialize(i, l, iv, g)
57
+ @id = i
58
+ @length = l
59
+ @invoke = iv
60
+ @group = g
61
+ end
59
62
  end
60
- end
61
63
 
62
- #
63
- # 形態素の連接コスト表クラス
64
- #
65
- class Matrix
66
- # コンストラクタ
67
- # data_dir:: 辞書ファイルのディレクトリパス
68
- def initialize(data_dir)
69
- fmis = FileMappedInputStream.new(data_dir + "/matrix.bin")
70
- @left_size = fmis.get_int
71
- @right_size = fmis.get_int
72
- @matrix = fmis.get_short_array(@left_size * @right_size)
73
- fmis.close
74
- end
64
+ #
65
+ # 形態素の連接コスト表クラス
66
+ #
67
+ class Matrix
68
+ # コンストラクタ
69
+ # data_dir:: 辞書ファイルのディレクトリパス
70
+ def initialize(data_dir)
71
+ fmis = FileMappedInputStream.new(data_dir + "/matrix.bin")
72
+ @left_size = fmis.get_int
73
+ @right_size = fmis.get_int
74
+ @matrix = fmis.get_short_array(@left_size * @right_size)
75
+ fmis.close
76
+ end
75
77
 
76
- # 形態素同士の連接コストを求める
77
- # left_id:: 左文脈ID
78
- # right_id:: 右文脈ID
79
- def link_cost(left_id, right_id)
80
- return @matrix[right_id * @right_size + left_id]
78
+ # 形態素同士の連接コストを求める
79
+ # left_id:: 左文脈ID
80
+ # right_id:: 右文脈ID
81
+ def link_cost(left_id, right_id)
82
+ return @matrix[right_id * @right_size + left_id]
83
+ end
81
84
  end
82
- end
83
85
 
84
- #
85
- # 未知語の検索を行うクラス
86
- #
87
- class Unknown
86
+ #
87
+ # 未知語の検索を行うクラス
88
+ #
89
+ class Unknown
88
90
 
89
- # コンストラクタ
90
- #data_dir:: 辞書ファイルのディレクトリパス
91
- def initialize(data_dir)
92
- # 文字カテゴリ管理クラス
93
- @category = CharCategory.new(data_dir)
91
+ # コンストラクタ
92
+ #data_dir:: 辞書ファイルのディレクトリパス
93
+ def initialize(data_dir)
94
+ # 文字カテゴリ管理クラス
95
+ @category = CharCategory.new(data_dir)
94
96
 
95
- # 文字カテゴリが空白の文字のID
96
- @space_id = @category.category(' '.unpack("U*")[0]).id
97
- end
97
+ # 文字カテゴリが空白の文字のID
98
+ @space_id = @category.category(' '.unpack("U*")[0]).id
99
+ end
98
100
 
99
- # 検索
100
- def search(text, start, wdic, result)
101
- txt = text.unpack("U*")
102
- length = txt.size
103
- ch = txt[start]
104
- ct = @category.category(ch)
101
+ # 検索
102
+ #text::
103
+ #start::
104
+ #wdic::
105
+ #result::
106
+ def search(text, start, wdic, result)
107
+ txt = text.unpack("U*")
108
+ length = txt.size
109
+ ch = txt[start]
110
+ ct = @category.category(ch)
105
111
 
106
- if !result.empty? and !ct.invoke
107
- return
108
- end
112
+ if !result.empty? and !ct.invoke
113
+ return
114
+ end
109
115
 
110
- is_space = (ct.id == @space_id)
111
- limit = [length, ct.length + start].min
116
+ is_space = (ct.id == @space_id)
117
+ limit = [length, ct.length + start].min
112
118
 
113
- for i in start..(limit - 1)
114
- wdic.search_from_trie_id(ct.id, start, (i - start) + 1, is_space, result)
119
+ for i in start..(limit - 1)
120
+ wdic.search_from_trie_id(ct.id, start, (i - start) + 1, is_space, result)
115
121
 
116
- if((i + 1) != limit and !(@category.compatible?(ch, text[i + 1])))
117
- return
122
+ if((i + 1) != limit and !(@category.compatible?(ch, text[i + 1])))
123
+ return
124
+ end
118
125
  end
119
- end
120
126
 
121
- if ct.group and limit < length
122
- for i in limit..(length - 1)
123
- if not @category.compatible?(ch, txt[i])
124
- wdic.search_from_trie_id(ct.id, start, i - start, is_space, result)
125
- return
127
+ if ct.group and limit < length
128
+ for i in limit..(length - 1)
129
+ if not @category.compatible?(ch, txt[i])
130
+ wdic.search_from_trie_id(ct.id, start, i - start, is_space, result)
131
+ return
132
+ end
126
133
  end
134
+ wdic.search_from_trie_id(ct.id, start, length - start, is_space, result)
127
135
  end
128
- wdic.search_from_trie_id(ct.id, start, length - start, is_space, result)
129
136
  end
130
137
  end
131
- end
132
138
 
133
- class WordDic
134
- # コンストラクタ
135
- #data_dir:: 辞書ファイルのディレクトリパス
136
- def initialize(data_dir)
137
- @trie = Searcher.new(data_dir + "/word2id")
138
- @data = FileMappedInputStream.get_string(data_dir + "/word.dat")
139
- @indices = FileMappedInputStream.get_int_array(data_dir + "/word.ary.idx")
139
+ class WordDic
140
+ # コンストラクタ
141
+ #data_dir:: 辞書ファイルのディレクトリパス
142
+ def initialize(data_dir)
143
+ @trie = Searcher.new(data_dir + "/word2id")
144
+ @data = FileMappedInputStream.get_string(data_dir + "/word.dat")
145
+ @indices = FileMappedInputStream.get_int_array(data_dir + "/word.ary.idx")
140
146
 
141
- fmis = FileMappedInputStream.new(data_dir + "/word.inf")
142
- word_count = fmis.size / (4 + 2 + 2 + 2)
143
- @data_offsets = fmis.get_int_array(word_count) # 単語の素性データの開始位置
144
- @left_ids = fmis.get_short_array(word_count) # 単語の左文脈ID
145
- @right_ids = fmis.get_short_array(word_count) # 単語の右文脈ID
146
- @costs = fmis.get_short_array(word_count) # 単語のコスト
147
- fmis.close
148
- end
147
+ fmis = FileMappedInputStream.new(data_dir + "/word.inf")
148
+ word_count = fmis.size / (4 + 2 + 2 + 2)
149
+ @data_offsets = fmis.get_int_array(word_count) # 単語の素性データの開始位置
150
+ @left_ids = fmis.get_short_array(word_count) # 単語の左文脈ID
151
+ @right_ids = fmis.get_short_array(word_count) # 単語の右文脈ID
152
+ @costs = fmis.get_short_array(word_count) # 単語のコスト
153
+ fmis.close
154
+ end
149
155
 
150
- def cost(word_id)
151
- return @costs[word_id]
152
- end
156
+ def cost(word_id)
157
+ return @costs[word_id]
158
+ end
153
159
 
154
- def search(text, start, result)
155
- indices = @indices
156
- left_ids = @left_ids
157
- right_ids = @right_ids
160
+ def search(text, start, result)
161
+ indices = @indices
162
+ left_ids = @left_ids
163
+ right_ids = @right_ids
158
164
 
159
- @trie.each_common_prefix(text, start, Proc.new { |start, offset, trie_id|
160
- ed = @indices[trie_id + 1]
165
+ @trie.each_common_prefix(text, start, Proc.new { |start, offset, trie_id|
166
+ ed = @indices[trie_id + 1]
161
167
 
162
- for i in indices[trie_id]..(ed - 1)
163
- result.push(ViterbiNode.new(i, start, offset, @left_ids[i], right_ids[i], false))
164
- end
165
- })
166
- end
168
+ for i in indices[trie_id]..(ed - 1)
169
+ result.push(ViterbiNode.new(i, start, offset, @left_ids[i], right_ids[i], false))
170
+ end
171
+ })
172
+ end
167
173
 
168
- def search_from_trie_id(trie_id, start, word_length, is_space, result)
169
- ed = @indices[trie_id + 1]
170
- for i in @indices[trie_id]..(ed - 1)
171
- result.push(ViterbiNode.new(i, start, word_length, @left_ids[i], @right_ids[i], is_space))
174
+ def search_from_trie_id(trie_id, start, word_length, is_space, result)
175
+ ed = @indices[trie_id + 1]
176
+ for i in @indices[trie_id]..(ed - 1)
177
+ result.push(ViterbiNode.new(i, start, word_length, @left_ids[i], @right_ids[i], is_space))
178
+ end
172
179
  end
173
- end
174
180
 
175
- def word_data(word_id)
176
- return @data.slice(@data_offsets[word_id]*2..@data_offsets[word_id + 1]*2 - 1)
181
+ def word_data(word_id)
182
+ return @data.slice(@data_offsets[word_id]*2..@data_offsets[word_id + 1]*2 - 1)
183
+ end
177
184
  end
178
185
  end
179
-
@@ -1,3 +1,4 @@
1
+ # coding: utf-8
1
2
  #形態素解析と分かち書きを行う機能の実装
2
3
 
3
4
  require 'igo/dictionary'
@@ -1,201 +1,210 @@
1
+ # coding: utf-8
1
2
  require 'igo/util'
2
3
 
4
+ #
5
+ #Stringクラスの拡張
6
+ #
3
7
  class String
8
+ # 文字列がパラメタの接頭辞で開始するかどうかを返却する
9
+ #prefix:: 接頭辞
10
+ #return:: true - 接頭辞で開始する
4
11
  def starts_with?(prefix)
5
12
  prefix = prefix.to_s
6
13
  self[0, prefix.length] == prefix
7
14
  end
8
15
  end
9
16
 
10
- #
11
- #DoubleArrayのノード用の定数などが定義されているクラス
12
- #
13
- class Node
17
+ module Igo
18
+
14
19
  #
15
- #BASEノード用のメソッドが定義されているクラス
20
+ #DoubleArrayのノード用の定数などが定義されているクラス
16
21
  #
17
- class Base
18
- #BASEノードに格納するID値をエンコードする
19
- def self.ids(nid)
20
- return (-1 * nid) - 1
22
+ class Node
23
+ #
24
+ #BASEノード用のメソッドが定義されているクラス
25
+ #
26
+ class Base
27
+ #BASEノードに格納するID値をエンコードする
28
+ def self.ids(nid)
29
+ return (-1 * nid) - 1
30
+ end
21
31
  end
22
- end
23
32
 
24
- #
25
- #CHECKノード用の定数が定義されているクラス
26
- #
27
- class Chck
28
- #文字列の終端文字コード
29
- #この文字はシステムにより予約されており、辞書内の形態素の表層形および解析対象テキストに含まれていた場合の動作は未定義
30
- TERMINATE_CODE = 0
31
- #文字列の終端を表す文字定数
32
- TERMINATE_CHAR = TERMINATE_CODE.chr
33
- #CHECKノードが未使用であることを示す文字コード
34
- #この文字はシステムにより予約されており、辞書内の形態素の表層形および解析対象テキストに含まれていた場合の動作は未定義
35
- VACANT_CODE = 1
36
- #使用可能な文字の最大値
37
- CODE_LIMIT = 0xffff
33
+ #
34
+ #CHECKノード用の定数が定義されているクラス
35
+ #
36
+ class Chck
37
+ #文字列の終端文字コード
38
+ #この文字はシステムにより予約されており、辞書内の形態素の表層形および解析対象テキストに含まれていた場合の動作は未定義
39
+ TERMINATE_CODE = 0
40
+ #文字列の終端を表す文字定数
41
+ TERMINATE_CHAR = TERMINATE_CODE.chr
42
+ #CHECKノードが未使用であることを示す文字コード
43
+ #この文字はシステムにより予約されており、辞書内の形態素の表層形および解析対象テキストに含まれていた場合の動作は未定義
44
+ VACANT_CODE = 1
45
+ #使用可能な文字の最大値
46
+ CODE_LIMIT = 0xffff
47
+ end
38
48
  end
39
- end
40
49
 
41
- #
42
- #文字列を文字のストリームとして扱うためのクラス
43
- #* readメソッドで個々の文字を順に読み込み、文字列の終端に達した場合にはNode::Chck::TERMINATE_CODEが返される。
44
- #
45
- class KeyStream
46
-
47
- def initialize(key, start = 0)
48
- @s = key
49
- @cur = start
50
- @len = key.unpack("U*").size
51
- end
52
-
53
- def compare_to(ks)
54
- return rest.compare_to(ks.rest)
55
- end
50
+ #
51
+ #文字列を文字のストリームとして扱うためのクラス
52
+ #* readメソッドで個々の文字を順に読み込み、文字列の終端に達した場合にはNode::Chck::TERMINATE_CODEが返される。
53
+ #
54
+ class KeyStream
56
55
 
57
- #このメソッドは動作的には、rest().starts_with?(prefix.substring(beg, len))と等価。
58
- #ほんの若干だが、パフォーマンスを改善するために導入。
59
- #簡潔性のためになくしても良いかもしれない。
60
- def start_with(prefix, beg, len)
61
- s = @s
62
- c = @cur
63
- if @len - c < len
64
- return false
56
+ def initialize(key, start = 0)
57
+ @s = key
58
+ @cur = start
59
+ @len = key.unpack("U*").size
65
60
  end
66
- word = s.unpack("U*")[c]
67
- if word.nil?
68
- return (prefix.slice(beg, len-beg) == nil)
69
- else
70
- [word].pack("U*").starts_with?(prefix.slice(beg, len-beg))
61
+
62
+ def compare_to(ks)
63
+ return rest.compare_to(ks.rest)
71
64
  end
72
- end
73
65
 
74
- def rest
75
- return @s.slice(@cur, @s.length)
76
- end
66
+ #このメソッドは動作的には、rest().starts_with?(prefix.substring(beg, len))と等価。
67
+ #ほんの若干だが、パフォーマンスを改善するために導入。
68
+ #簡潔性のためになくしても良いかもしれない。
69
+ def start_with(prefix, beg, len)
70
+ s = @s
71
+ c = @cur
72
+ if @len - c < len
73
+ return false
74
+ end
75
+ word = s.unpack("U*")[c]
76
+ if word.nil?
77
+ return (prefix.slice(beg, len-beg) == nil)
78
+ else
79
+ [word].pack("U*").starts_with?(prefix.slice(beg, len-beg))
80
+ end
81
+ end
82
+
83
+ def rest
84
+ return @s.slice(@cur, @s.length)
85
+ end
77
86
 
78
- def read
87
+ def read
79
88
 
80
- if eos?
81
- return Node::Chck::TERMINATE_CODE
82
- else
83
- r = @s.unpack("U*")[@cur]
84
- result = [r].pack("U*")
85
- @cur += 1
86
- return r
89
+ if eos?
90
+ return Node::Chck::TERMINATE_CODE
91
+ else
92
+ r = @s.unpack("U*")[@cur]
93
+ result = [r].pack("U*")
94
+ @cur += 1
95
+ return r
96
+ end
87
97
  end
88
- end
89
98
 
90
- def eos?
91
- return (@cur == @len) ? true : false
99
+ def eos?
100
+ return (@cur == @len) ? true : false
101
+ end
92
102
  end
93
- end
94
103
 
95
- #
96
- # DoubleArray検索用のクラス
97
- #
98
- class Searcher
99
- #保存されているDoubleArrayを読み込んで、このクラスのインスタンスを作成する
100
- #path:: DoubleArrayが保存されているファイルのパス
101
- def initialize(path)
102
- fmis = FileMappedInputStream.new(path)
103
- node_size = fmis.get_int()
104
- tind_size = fmis.get_int()
105
- tail_size = fmis.get_int()
106
- @key_set_size = tind_size
107
- @begs = fmis.get_int_array(tind_size)
108
- @base = fmis.get_int_array(node_size)
109
- @lens = fmis.get_short_array(tind_size)
110
- @chck = fmis.get_char_array(node_size)
111
- @tail = fmis.get_string(tail_size)
112
- fmis.close
113
- end
104
+ #
105
+ # DoubleArray検索用のクラス
106
+ #
107
+ class Searcher
108
+ #保存されているDoubleArrayを読み込んで、このクラスのインスタンスを作成する
109
+ #path:: DoubleArrayが保存されているファイルのパス
110
+ def initialize(path)
111
+ fmis = FileMappedInputStream.new(path)
112
+ node_size = fmis.get_int()
113
+ tind_size = fmis.get_int()
114
+ tail_size = fmis.get_int()
115
+ @key_set_size = tind_size
116
+ @begs = fmis.get_int_array(tind_size)
117
+ @base = fmis.get_int_array(node_size)
118
+ @lens = fmis.get_short_array(tind_size)
119
+ @chck = fmis.get_char_array(node_size)
120
+ @tail = fmis.get_string(tail_size)
121
+ fmis.close
122
+ end
114
123
 
115
- #DoubleArrayに格納されているキーの数を返却
116
- #return:: DoubleArrayに格納されているキーの数
117
- def size
118
- return @key_set_size
119
- end
124
+ #DoubleArrayに格納されているキーの数を返却
125
+ #return:: DoubleArrayに格納されているキーの数
126
+ def size
127
+ return @key_set_size
128
+ end
120
129
 
121
- #キーを検索する
122
- #key:: 検索対象のキー文字列
123
- #return:: キーが見つかった場合はそのIDを、見つからなかった場合は-1を返す
124
- def search(key)
125
- base = @base
126
- chck = @chck
127
- node = @base[0]
128
- kin = KeyStream.new(key)
130
+ #キーを検索する
131
+ #key:: 検索対象のキー文字列
132
+ #return:: キーが見つかった場合はそのIDを、見つからなかった場合は-1を返す
133
+ def search(key)
134
+ base = @base
135
+ chck = @chck
136
+ node = @base[0]
137
+ kin = KeyStream.new(key)
129
138
 
130
- while true
131
- code = kin.read
132
- idx = node + code
133
- node = base[idx]
139
+ while true
140
+ code = kin.read
141
+ idx = node + code
142
+ node = base[idx]
134
143
 
135
- if(chck[idx] == code)
136
- if(node >= 0)
137
- next
138
- elsif(kin.eos? or key_exists?(kin, node))
139
- return Node::Base.ids(node)
144
+ if(chck[idx] == code)
145
+ if(node >= 0)
146
+ next
147
+ elsif(kin.eos? or key_exists?(kin, node))
148
+ return Node::Base.ids(node)
149
+ end
150
+ return -1
140
151
  end
141
- return -1
142
152
  end
143
153
  end
144
- end
145
154
 
146
- #common-prefix検索を行う
147
- #* 条件に一致するキーが見つかる度に、callback.callメソッドが呼び出される
148
- #key:: 検索対象のキー文字列
149
- #start:: 検索対象となるキー文字列の最初の添字
150
- #callback:: 一致を検出した場合に呼び出されるコールバックメソッド
151
- def each_common_prefix(key, start, callback)
152
- base = @base
153
- chck = @chck
154
- node = @base[0]
155
- offset = -1
156
- kin = KeyStream.new(key, start)
155
+ #common-prefix検索を行う
156
+ #* 条件に一致するキーが見つかる度に、callback.callメソッドが呼び出される
157
+ #key:: 検索対象のキー文字列
158
+ #start:: 検索対象となるキー文字列の最初の添字
159
+ #callback:: 一致を検出した場合に呼び出されるコールバックメソッド
160
+ def each_common_prefix(key, start, callback)
161
+ base = @base
162
+ chck = @chck
163
+ node = @base[0]
164
+ offset = -1
165
+ kin = KeyStream.new(key, start)
157
166
 
158
- while true
159
- code = kin.read
160
- offset += 1
161
- terminal_index = node
167
+ while true
168
+ code = kin.read
169
+ offset += 1
170
+ terminal_index = node
162
171
 
163
- if(chck[terminal_index] == Node::Chck::TERMINATE_CODE)
164
- callback.call(start, offset, Node::Base.ids(base[terminal_index]))
172
+ if(chck[terminal_index] == Node::Chck::TERMINATE_CODE)
173
+ callback.call(start, offset, Node::Base.ids(base[terminal_index]))
165
174
 
166
- if(code == Node::Chck::TERMINATE_CODE)
167
- return
175
+ if(code == Node::Chck::TERMINATE_CODE)
176
+ return
177
+ end
168
178
  end
169
- end
170
179
 
171
- idx = node + code
172
- node = base[idx]
180
+ idx = node + code
181
+ node = base[idx]
173
182
 
174
- if(chck[idx] == code)
175
- if(node >= 0)
176
- next
177
- else
178
- call_if_key_including(kin, node, start, offset, callback)
183
+ if(chck[idx] == code)
184
+ if(node >= 0)
185
+ next
186
+ else
187
+ call_if_key_including(kin, node, start, offset, callback)
188
+ end
179
189
  end
190
+ return
180
191
  end
181
- return
182
192
  end
183
- end
184
193
 
185
- private
194
+ private
186
195
 
187
- def call_if_key_including(kin, node, start, offset, callback)
188
- node_id = Node::Base.ids(node)
189
- if(kin.start_with(@tail, @begs[node_id], @lens[node_id]))
190
- callback.call(start, offset + @lens[node_id] + 1, node_id)
196
+ def call_if_key_including(kin, node, start, offset, callback)
197
+ node_id = Node::Base.ids(node)
198
+ if(kin.start_with(@tail, @begs[node_id], @lens[node_id]))
199
+ callback.call(start, offset + @lens[node_id] + 1, node_id)
200
+ end
191
201
  end
192
- end
193
202
 
194
- def key_exists?(kin, node)
195
- nid = Node.Base.ids(node)
196
- beg = @begs[nid]
197
- s = @tail.slice(beg, beg + @lens[nid])
198
- return kin.rest == s ? true : false
203
+ def key_exists?(kin, node)
204
+ nid = Node.Base.ids(node)
205
+ beg = @begs[nid]
206
+ s = @tail.slice(beg, beg + @lens[nid])
207
+ return kin.rest == s ? true : false
208
+ end
199
209
  end
200
210
  end
201
-
@@ -1,93 +1,96 @@
1
- # ファイルユーティリティ
1
+ # coding: utf-8
2
+ #= ファイルユーティリティ
2
3
 
3
- #
4
- #=== ファイルにマッピングされた入力ストリーム
5
- # ファイルからバイナリデータを取得する場合、必ずこのクラスが使用される。
6
- #
7
- class FileMappedInputStream
8
- # 入力ストリームの初期化
9
- # path:: 入力ファイルのパス
10
- def initialize(path)
11
- @path = path
12
- @cur = 0
13
- @file = open(path, "rb")
14
- end
4
+ module Igo
5
+ #
6
+ #=== ファイルにマッピングされた入力ストリーム
7
+ # ファイルからバイナリデータを取得する場合、必ずこのクラスが使用される。
8
+ #
9
+ class FileMappedInputStream
10
+ # 入力ストリームの初期化
11
+ # path:: 入力ファイルのパス
12
+ def initialize(path)
13
+ @path = path
14
+ @cur = 0
15
+ @file = open(path, "rb")
16
+ end
15
17
 
16
- # int値で読み取り
17
- def get_int()
18
- return @file.read(4).unpack("i*")[0]
19
- end
18
+ # int値で読み取り
19
+ def get_int()
20
+ return @file.read(4).unpack("i*")[0]
21
+ end
22
+
23
+ # int配列で読み取り
24
+ # count:: 読み取りカウント
25
+ def get_int_array(count)
26
+ return @file.read(count * 4).unpack("i*")
27
+ end
20
28
 
21
- # int配列で読み取り
22
- # count:: 読み取りカウント
23
- def get_int_array(count)
24
- return @file.read(count * 4).unpack("i*")
25
- end
29
+ # int配列で読み取り
30
+ # path:: 入力ファイルのパス
31
+ def self.get_int_array(path)
32
+ fmis = FileMappedInputStream.new(path)
33
+ array = fmis.get_int_array((File::stat(path).size)/4)
34
+ fmis.close
35
+ return array
36
+ end
26
37
 
27
- # int配列で読み取り
28
- # path:: 入力ファイルのパス
29
- def self.get_int_array(path)
30
- fmis = FileMappedInputStream.new(path)
31
- array = fmis.get_int_array((File::stat(path).size)/4)
32
- fmis.close
33
- return array
34
- end
38
+ # short配列で読み取り
39
+ # count:: 読み取りカウント
40
+ def get_short_array(count)
41
+ return @file.read(count * 2).unpack("s*")
42
+ end
35
43
 
36
- # short配列で読み取り
37
- # count:: 読み取りカウント
38
- def get_short_array(count)
39
- return @file.read(count * 2).unpack("s*")
40
- end
44
+ # char配列で読み取り
45
+ # count:: 読み取りカウント
46
+ def get_char_array(count)
47
+ return @file.read(count * 2).unpack("S!*")
48
+ end
41
49
 
42
- # char配列で読み取り
43
- # count:: 読み取りカウント
44
- def get_char_array(count)
45
- return @file.read(count * 2).unpack("S!*")
46
- end
50
+ # stringで読み取り
51
+ # count:: 読み取りカウント
52
+ def get_string(count)
53
+ return @file.read(count * 2)
54
+ end
47
55
 
48
- # stringで読み取り
49
- # count:: 読み取りカウント
50
- def get_string(count)
51
- return @file.read(count * 2)
52
- end
53
-
54
- # stringで読み取り
55
- # path:: 入力ファイル
56
- def self.get_string(path)
57
- fmis = FileMappedInputStream.new(path)
58
- str = fmis.get_string((File::stat(path).size)/2)
59
- fmis.close
56
+ # stringで読み取り
57
+ # path:: 入力ファイル
58
+ def self.get_string(path)
59
+ fmis = FileMappedInputStream.new(path)
60
+ str = fmis.get_string((File::stat(path).size)/2)
61
+ fmis.close
60
62
 
61
- return str
62
- end
63
+ return str
64
+ end
63
65
 
64
- # 入力ファイルのサイズを返却する
65
- def size
66
- return File::stat(@path).size
67
- end
66
+ # 入力ファイルのサイズを返却する
67
+ def size
68
+ return File::stat(@path).size
69
+ end
68
70
 
69
- # 入力ストリームを閉じる
70
- #* newした場合、必ずcloseを呼ぶこと
71
- def close
72
- @file.close
73
- end
71
+ # 入力ストリームを閉じる
72
+ #* newした場合、必ずcloseを呼ぶこと
73
+ def close
74
+ @file.close
75
+ end
74
76
 
75
- # char配列で読み取り
76
- # path:: 入力ファイル
77
- def self.get_char_array(path)
78
- fmis = FileMappedInputStream.new(path)
79
- array = fmis.get_char_array(fmis.size / 2)
80
- fmis.close
81
- return array
82
- end
77
+ # char配列で読み取り
78
+ # path:: 入力ファイル
79
+ def self.get_char_array(path)
80
+ fmis = FileMappedInputStream.new(path)
81
+ array = fmis.get_char_array(fmis.size / 2)
82
+ fmis.close
83
+ return array
84
+ end
83
85
 
84
- private
86
+ private
85
87
 
86
- # ファイルマップ
87
- #* 現在、不使用
88
- def map(size)
89
- @file.pos = @cur
90
- @cur += size
91
- return @file.read(size)
88
+ # ファイルマップ
89
+ #* 現在、不使用
90
+ def map(size)
91
+ @file.pos = @cur
92
+ @cur += size
93
+ return @file.read(size)
94
+ end
92
95
  end
93
- end
96
+ end
@@ -0,0 +1,17 @@
1
+ # coding: utf-8
2
+ module Igo
3
+ #
4
+ #バージョンクラス
5
+ #
6
+ class Version
7
+ #igo-rubyのRubyGemsバージョンを出力する
8
+ def self.igo_ruby
9
+ version_file = File.dirname(__FILE__) + '/../../VERSION'
10
+ version = ""
11
+ open(version_file) { |igo_ruby_version|
12
+ version = igo_ruby_version.gets
13
+ }
14
+ return version
15
+ end
16
+ end
17
+ end
@@ -1,9 +1,16 @@
1
+ # coding: utf-8
1
2
  require 'rubygems'
2
3
  require 'igo-ruby'
3
- tagger = Igo::Tagger.new('../../ipadic')
4
+ #require File.dirname(__FILE__) + '/../lib/igo-ruby'
5
+
6
+ puts "version -> #{Igo::Version.igo_ruby}"
7
+
8
+ tagger = Igo::Tagger.new(File.dirname(__FILE__) + '/../../ipadic')
4
9
  t = tagger.parse('吾輩は猫である。名前はまだ無い。')
10
+ puts "parse ->"
5
11
  t.each{|m|
6
12
  puts "#{m.surface} #{m.feature} #{m.start}"
7
13
  }
14
+ puts "wakati ->"
8
15
  t = tagger.wakati('どこで生れたかとんと見当がつかぬ。')
9
- puts t.join(' ')
16
+ puts t.join(' ')
metadata CHANGED
@@ -1,13 +1,8 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: igo-ruby
3
3
  version: !ruby/object:Gem::Version
4
- hash: 31
5
- prerelease: false
6
- segments:
7
- - 0
8
- - 1
9
- - 2
10
- version: 0.1.2
4
+ prerelease:
5
+ version: 0.1.3
11
6
  platform: ruby
12
7
  authors:
13
8
  - K.Nishi
@@ -15,71 +10,53 @@ autorequire:
15
10
  bindir: bin
16
11
  cert_chain: []
17
12
 
18
- date: 2010-12-13 00:00:00 +09:00
13
+ date: 2011-02-10 00:00:00 +09:00
19
14
  default_executable:
20
15
  dependencies:
21
16
  - !ruby/object:Gem::Dependency
22
- prerelease: false
23
- version_requirements: &id001 !ruby/object:Gem::Requirement
17
+ name: rspec
18
+ requirement: &id001 !ruby/object:Gem::Requirement
24
19
  none: false
25
20
  requirements:
26
21
  - - ~>
27
22
  - !ruby/object:Gem::Version
28
- hash: 11
29
- segments:
30
- - 2
31
- - 1
32
- - 0
33
23
  version: 2.1.0
34
- name: rspec
35
- requirement: *id001
36
24
  type: :development
37
- - !ruby/object:Gem::Dependency
38
25
  prerelease: false
39
- version_requirements: &id002 !ruby/object:Gem::Requirement
26
+ version_requirements: *id001
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: &id002 !ruby/object:Gem::Requirement
40
30
  none: false
41
31
  requirements:
42
32
  - - ~>
43
33
  - !ruby/object:Gem::Version
44
- hash: 23
45
- segments:
46
- - 1
47
- - 0
48
- - 0
49
34
  version: 1.0.0
50
- name: bundler
51
- requirement: *id002
52
35
  type: :development
53
- - !ruby/object:Gem::Dependency
54
36
  prerelease: false
55
- version_requirements: &id003 !ruby/object:Gem::Requirement
37
+ version_requirements: *id002
38
+ - !ruby/object:Gem::Dependency
39
+ name: jeweler
40
+ requirement: &id003 !ruby/object:Gem::Requirement
56
41
  none: false
57
42
  requirements:
58
43
  - - ~>
59
44
  - !ruby/object:Gem::Version
60
- hash: 1
61
- segments:
62
- - 1
63
- - 5
64
- - 1
65
45
  version: 1.5.1
66
- name: jeweler
67
- requirement: *id003
68
46
  type: :development
69
- - !ruby/object:Gem::Dependency
70
47
  prerelease: false
71
- version_requirements: &id004 !ruby/object:Gem::Requirement
48
+ version_requirements: *id003
49
+ - !ruby/object:Gem::Dependency
50
+ name: rcov
51
+ requirement: &id004 !ruby/object:Gem::Requirement
72
52
  none: false
73
53
  requirements:
74
54
  - - ">="
75
55
  - !ruby/object:Gem::Version
76
- hash: 3
77
- segments:
78
- - 0
79
56
  version: "0"
80
- name: rcov
81
- requirement: *id004
82
57
  type: :development
58
+ prerelease: false
59
+ version_requirements: *id004
83
60
  description: "\n Ruby port of Igo Japanese morphological analyzer. Igo-ruby needs Igo's binary dictionary files.\n These files created by Java programs.\n See: http://igo.sourceforge.jp/\n "
84
61
  email: 24signals@gmail.com
85
62
  executables: []
@@ -101,6 +78,7 @@ files:
101
78
  - lib/igo/tagger.rb
102
79
  - lib/igo/trie.rb
103
80
  - lib/igo/util.rb
81
+ - lib/igo/version.rb
104
82
  - spec/igo-ruby_spec.rb
105
83
  - spec/spec_helper.rb
106
84
  - test/test.rb
@@ -120,7 +98,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
120
98
  requirements:
121
99
  - - ">="
122
100
  - !ruby/object:Gem::Version
123
- hash: 3
101
+ hash: 2664330083952194465
124
102
  segments:
125
103
  - 0
126
104
  version: "0"
@@ -129,16 +107,11 @@ required_rubygems_version: !ruby/object:Gem::Requirement
129
107
  requirements:
130
108
  - - ">"
131
109
  - !ruby/object:Gem::Version
132
- hash: 23
133
- segments:
134
- - 1
135
- - 3
136
- - 6
137
110
  version: 1.3.6
138
111
  requirements: []
139
112
 
140
113
  rubyforge_project:
141
- rubygems_version: 1.3.7
114
+ rubygems_version: 1.5.0
142
115
  signing_key:
143
116
  specification_version: 3
144
117
  summary: Ruby port of Igo Japanese morphological analyzer.