igo-ruby 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/Rakefile CHANGED
@@ -16,7 +16,11 @@ Jeweler::Tasks.new do |gem|
16
16
  gem.homepage = "http://github.com/kyow/igo-ruby"
17
17
  gem.license = "MIT"
18
18
  gem.summary = %Q{Ruby port of Igo Japanese morphological analyzer.}
19
- gem.description = %Q{Ruby port of Igo Japanese morphological analyzer.}
19
+ gem.description = %Q{
20
+ Ruby port of Igo Japanese morphological analyzer. Igo-ruby needs Igo's binary dictionary files.
21
+ These files created by Java programs.
22
+ See: http://igo.sourceforge.jp/
23
+ }
20
24
  gem.email = "24signals@gmail.com"
21
25
  gem.authors = ["K.Nishi"]
22
26
  # Include your dependencies below. Runtime dependencies are required when using your gem,
@@ -26,6 +30,7 @@ Jeweler::Tasks.new do |gem|
26
30
 
27
31
  gem.files = Rake::FileList.new('lib/**/*.rb', '[A-Z]*')
28
32
  gem.required_rubygems_version = ">1.3.6"
33
+ gem.rdoc_options << '-c UTF-8' << '-S' << '-U'
29
34
  end
30
35
  Jeweler::RubygemsDotOrgTasks.new
31
36
 
@@ -50,4 +55,6 @@ Rake::RDocTask.new do |rdoc|
50
55
  rdoc.title = "igo-ruby #{version}"
51
56
  rdoc.rdoc_files.include('README*')
52
57
  rdoc.rdoc_files.include('lib/**/*.rb')
58
+
59
+ rdoc.options << '-c UTF-8' << '-S' << '-U'
53
60
  end
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.0
1
+ 0.1.1
@@ -1,9 +1,39 @@
1
+ #
2
+ #= 形態素解析エンジンIgoのRuby実装
3
+ #解析結果がほぼMeCab互換の形態素解析エンジン"Igo"のRuby実装
4
+ #
5
+ #Copyright:: Copyright (C) K.Nishi, 2010. All rights reserved.
6
+ #Authors:: K.Nishi
7
+ #License:: MIT License ただし、使用する辞書のライセンスに関しては、辞書配布元のそれに準ずる
8
+ #
9
+ #== 注意
10
+ #igo-rubyには辞書ファイルを生成する機能はありません。
11
+ #Igoで生成した辞書ファイルを使用してください。
12
+ #
13
+ #== 公開
14
+ #* RubyGems
15
+ # * igo-ruby[https://rubygems.org/gems/igo-ruby]
16
+ #* ソース(github)
17
+ # * {kyow/igo-ruby}[https://github.com/kyow/igo-ruby]
18
+ #
19
+ #== 参照
20
+ #* Igo
21
+ # 1. {Igo - Java形態素解析器}[http://igo.sourceforge.jp/index.html]
22
+ # 2. {Igo}[http://sourceforge.jp/projects/igo/releases/]
23
+ #* Igo-python
24
+ # 1. {igo-python 0.3a}[http://pypi.python.org/pypi/igo-python/0.3a]
25
+ # 2. {Igo Japanease morphological analyzer for python}[https://launchpad.net/igo-python/]
26
+ #
27
+
1
28
  $:.unshift(File.dirname(__FILE__))
2
29
 
3
30
  require 'nkf'
4
31
  require 'jcode'
5
32
  require 'kconv'
6
33
 
34
+ #
35
+ #== Igoモジュール
36
+ #
7
37
  module Igo
8
38
  autoload :Tagger, 'igo/tagger'
9
39
  end
@@ -1,21 +1,19 @@
1
- #require 'trie'
2
- #require 'util'
3
- #require 'nkf'
4
-
5
- # 辞書
1
+ #辞書クラス群
6
2
 
3
+ #
4
+ # Viterbiアルゴリズムで使用されるノードクラス
5
+ #
7
6
  class ViterbiNode
8
7
  attr_accessor :cost, :prev, :word_id, :start, :length, :left_id, :right_id, :is_space
9
8
  def initialize(word_id, start, length, left_id, right_id, is_space)
10
- @cost = 0
11
- @prev = nil
12
- @word_id = word_id
13
- @start = start
14
- @length = length
15
- @left_id = left_id
16
- @right_id = right_id
17
- @is_space = is_space
18
- # puts "==viterbinode #{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 # 形態素の文字種(文字カテゴリ)が空白かどうか
19
17
  end
20
18
 
21
19
  def self.make_BOSEOS
@@ -37,7 +35,6 @@ class CharCategory
37
35
  end
38
36
 
39
37
  def compatible?(code1, code2)
40
- # puts @eql_masks[code1] & @eql_masks[code2]
41
38
  return (@eql_masks[code1] & @eql_masks[code2]) != 0
42
39
  end
43
40
 
@@ -59,11 +56,15 @@ class Category
59
56
  @length = l
60
57
  @invoke = iv
61
58
  @group = g
62
- # puts "==category #{i} #{l} #{iv} #{g}"
63
59
  end
64
60
  end
65
61
 
62
+ #
63
+ # 形態素の連接コスト表クラス
64
+ #
66
65
  class Matrix
66
+ # コンストラクタ
67
+ # data_dir:: 辞書ファイルのディレクトリパス
67
68
  def initialize(data_dir)
68
69
  fmis = FileMappedInputStream.new(data_dir + "/matrix.bin")
69
70
  @left_size = fmis.get_int
@@ -72,40 +73,44 @@ class Matrix
72
73
  fmis.close
73
74
  end
74
75
 
76
+ # 形態素同士の連接コストを求める
77
+ # left_id:: 左文脈ID
78
+ # right_id:: 右文脈ID
75
79
  def link_cost(left_id, right_id)
76
80
  return @matrix[right_id * @right_size + left_id]
77
81
  end
78
82
  end
79
83
 
84
+ #
85
+ # 未知語の検索を行うクラス
86
+ #
80
87
  class Unknown
88
+
89
+ # コンストラクタ
90
+ #data_dir:: 辞書ファイルのディレクトリパス
81
91
  def initialize(data_dir)
92
+ # 文字カテゴリ管理クラス
82
93
  @category = CharCategory.new(data_dir)
94
+
95
+ # 文字カテゴリが空白の文字のID
83
96
  @space_id = @category.category(' '.unpack("U*")[0]).id
84
97
  end
85
98
 
99
+ # 検索
86
100
  def search(text, start, wdic, result)
87
101
  txt = text.unpack("U*")
88
102
  length = txt.size
89
103
  ch = txt[start]
90
104
  ct = @category.category(ch)
91
105
 
92
- # puts "Unknown.search ch=#{ch} length=#{length} start=#{start}"
93
- # p ct
94
- # p result
95
- # p ct.invoke
96
106
  if !result.empty? and !ct.invoke
97
- # puts "result return"
98
107
  return
99
108
  end
100
- # puts "---i"
101
109
 
102
110
  is_space = (ct.id == @space_id)
103
111
  limit = [length, ct.length + start].min
104
112
 
105
- # puts "limit = #{limit} #{length} #{ct.length}"
106
-
107
113
  for i in start..(limit - 1)
108
- # puts "[a]"
109
114
  wdic.search_from_trie_id(ct.id, start, (i - start) + 1, is_space, result)
110
115
 
111
116
  if((i + 1) != limit and !(@category.compatible?(ch, text[i + 1])))
@@ -114,23 +119,20 @@ class Unknown
114
119
  end
115
120
 
116
121
  if ct.group and limit < length
117
- # puts "[b]"
118
122
  for i in limit..(length - 1)
119
- # puts "[c] COMPATIBLE? #{ch} #{txt[i + 1]}"
120
-
121
123
  if not @category.compatible?(ch, txt[i])
122
- # puts "[d] #{i} #{start}"
123
124
  wdic.search_from_trie_id(ct.id, start, i - start, is_space, result)
124
125
  return
125
126
  end
126
127
  end
127
- # puts "[e] #{length} #{start}"
128
128
  wdic.search_from_trie_id(ct.id, start, length - start, is_space, result)
129
129
  end
130
130
  end
131
131
  end
132
132
 
133
133
  class WordDic
134
+ # コンストラクタ
135
+ #data_dir:: 辞書ファイルのディレクトリパス
134
136
  def initialize(data_dir)
135
137
  @trie = Searcher.new(data_dir + "/word2id")
136
138
  @data = FileMappedInputStream.get_string(data_dir + "/word.dat")
@@ -138,10 +140,10 @@ class WordDic
138
140
 
139
141
  fmis = FileMappedInputStream.new(data_dir + "/word.inf")
140
142
  word_count = fmis.size / (4 + 2 + 2 + 2)
141
- @data_offsets = fmis.get_int_array(word_count)
142
- @left_ids = fmis.get_short_array(word_count)
143
- @right_ids = fmis.get_short_array(word_count)
144
- @costs = fmis.get_short_array(word_count)
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) # 単語のコスト
145
147
  fmis.close
146
148
  end
147
149
 
@@ -171,17 +173,7 @@ class WordDic
171
173
  end
172
174
 
173
175
  def word_data(word_id)
174
- # s = UTFConverter.utf16to8(@data)
175
-
176
- # st = format("%x", @data_offsets[word_id] * 2)
177
- # ed = format("%x", @data_offsets[word_id + 1] * 2)
178
-
179
- # puts "WORD DATA: #{word_id} = #{st} : #{ed}"
180
- # p s
181
- # puts "nkf= " + NKF.nkf('-W16L0 --utf8', s)
182
- # p [s].pack("U*")
183
176
  return @data.slice(@data_offsets[word_id]*2..@data_offsets[word_id + 1]*2 - 1)
184
- # return NKF.nkf('-W16L0 --utf8', s)
185
177
  end
186
178
  end
187
179
 
@@ -1,144 +1,133 @@
1
+ #形態素解析と分かち書きを行う機能の実装
2
+
1
3
  require 'igo/dictionary'
2
4
  require 'igo/trie'
3
5
 
4
6
  module Igo
5
-
6
- class Morpheme
7
- attr_accessor :surface, :feature, :start
8
- def initialize(surface, feature, start)
9
- @surface = surface
10
- @feature = feature
11
- @start = start
12
- end
7
+ #
8
+ #形態素クラス
9
+ #
10
+ class Morpheme
11
+ attr_accessor :surface, :feature, :start
12
+
13
+ #surface:: 形態素の表層形
14
+ #feature:: 形態素の素性
15
+ #start:: テキスト内でも形態素の出現開始位置
16
+ def initialize(surface, feature, start)
17
+ @surface = surface
18
+ @feature = feature
19
+ @start = start
20
+ end
13
21
  end
14
22
 
15
- # 形態素解析を行う
16
- class Tagger
17
- def self.__BOS_NODES
18
- return [ViterbiNode.make_BOSEOS]
19
- end
20
-
21
- def initialize(dir)
22
- @wdc = WordDic.new(dir)
23
- @unk = Unknown.new(dir)
24
- @mtx = Matrix.new(dir)
25
- end
26
-
27
- #
28
- def parse(text, result=[])
29
- vn = impl(text, result)
30
- txt = text.unpack("U*")
31
- while vn
32
- surface = txt.slice(vn.start, vn.length).pack("U*")
23
+ #
24
+ #形態素解析を行うクラス
25
+ #
26
+ class Tagger
27
+ def self.__BOS_NODES
28
+ return [ViterbiNode.make_BOSEOS]
29
+ end
30
+
31
+ #dir:: 辞書ファイルのディレクトリパス
32
+ def initialize(dir)
33
+ @wdc = WordDic.new(dir)
34
+ @unk = Unknown.new(dir)
35
+ @mtx = Matrix.new(dir)
36
+ end
37
+
38
+ #形態素解析を行う
39
+ #text:: 解析対象テキスト
40
+ #result:: 解析結果の形態素が追加される配列
41
+ #return:: 解析結果の形態素配列
42
+ def parse(text, result=[])
43
+ vn = impl(text, result)
44
+ txt = text.unpack("U*")
45
+ while vn
46
+ surface = txt.slice(vn.start, vn.length).pack("U*")
33
47
 
34
- s = @wdc.word_data(vn.word_id)
48
+ s = @wdc.word_data(vn.word_id)
35
49
 
36
- # puts s.size
37
- feature = NKF.nkf('-W16L0 --utf8', s)
38
- # feature = @wdc.word_data(vn.word_id)
39
- result.push(Morpheme.new(surface, feature, vn.start))
40
- vn = vn.prev
50
+ feature = NKF.nkf('-W16L0 --utf8', s)
51
+ result.push(Morpheme.new(surface, feature, vn.start))
52
+ vn = vn.prev
53
+ end
54
+ return result
41
55
  end
42
- return result
43
- end
44
56
 
45
-
46
- # 分かち書きを行う
47
- def wakati(text, result=[])
48
- vn = impl(text, result)
49
- txt = text.unpack("U*")
57
+ #分かち書きを行う
58
+ #text:: 分かち書きされるテキスト
59
+ #result:: 分かち書き結果の文字列が追加される配列
60
+ #return:: 分かち書き結果の文字列の配列
61
+ def wakati(text, result=[])
62
+ vn = impl(text, result)
63
+ txt = text.unpack("U*")
50
64
 
51
- while vn
52
- # puts "s:#{vn.start} len:#{vn.length}"
53
- a = txt.slice(vn.start, vn.length).pack("U*")
54
- result.push(a)
55
- vn = vn.prev
65
+ while vn
66
+ a = txt.slice(vn.start, vn.length).pack("U*")
67
+ result.push(a)
68
+ vn = vn.prev
69
+ end
70
+ return result
56
71
  end
57
- return result
58
- end
59
72
 
60
- private
73
+ private
61
74
 
62
- def impl(text, result=[])
63
- txs = text.unpack("U*")
64
- len = txs.size
65
-
66
- # puts "len=#{len}"
75
+ def impl(text, result=[])
76
+ txs = text.unpack("U*")
77
+ len = txs.size
67
78
 
68
- node_ary = [Tagger.__BOS_NODES]
69
- for i in 0..(len-1)
70
- node_ary.push([])
71
- end
79
+ node_ary = [Tagger.__BOS_NODES]
80
+ for i in 0..(len-1)
81
+ node_ary.push([])
82
+ end
72
83
 
73
- for i in 0..(len-1)
74
- per_result = []
84
+ for i in 0..(len-1)
85
+ per_result = []
75
86
 
76
- # puts "==> node_ary[#{i}].length = #{!node_ary[i].empty?}"
77
- # p node_ary
78
- unless node_ary[i].empty?
79
- @wdc.search(text, i, per_result)
80
- # puts "---WDC---"
81
- # p per_result
82
- @unk.search(text, i, @wdc, per_result)
83
- # puts "---UNK---"
84
- # p per_result
85
- prevs = node_ary[i]
87
+ unless node_ary[i].empty?
88
+ @wdc.search(text, i, per_result)
89
+ @unk.search(text, i, @wdc, per_result)
90
+ prevs = node_ary[i]
86
91
 
87
- for j in 0..(per_result.size - 1)
88
- vn = per_result[j]
89
- # p vn
90
- if(vn.is_space)
91
- # puts "#{j} is space (#{i + vn.length}) i=#{i} len=#{vn.length}"
92
- node_ary[i + vn.length] = prevs
93
- # p node_ary
94
- # node_ary[i + vn.length].push(prevs)
95
- else
96
- # puts "#{j} is NOT space (#{i + vn.length}) i=#{i} len=#{vn.length}"
97
- node_ary[i + vn.length].push(set_min_cost_node(vn, prevs))
98
- # p node_ary
99
- # node_ary[i + vn.length] + set_min_cost_node(vn, prevs)
92
+ for j in 0..(per_result.size - 1)
93
+ vn = per_result[j]
94
+ if(vn.is_space)
95
+ node_ary[i + vn.length] = prevs
96
+ else
97
+ node_ary[i + vn.length].push(set_min_cost_node(vn, prevs))
98
+ end
100
99
  end
101
- # p node_ary
102
100
  end
103
101
  end
104
- end
105
102
 
106
- cur = set_min_cost_node(ViterbiNode.make_BOSEOS, node_ary[len]).prev
103
+ cur = set_min_cost_node(ViterbiNode.make_BOSEOS, node_ary[len]).prev
107
104
 
108
- # reverse
109
- head = nil
110
- while cur.prev
111
- tmp = cur.prev
112
- cur.prev = head
113
- head = cur
114
- cur = tmp
105
+ # reverse
106
+ head = nil
107
+ while cur.prev
108
+ tmp = cur.prev
109
+ cur.prev = head
110
+ head = cur
111
+ cur = tmp
112
+ end
113
+ return head
115
114
  end
116
- return head
117
-
118
- # return cur.reverse
119
-
120
- end
121
115
 
122
- def set_min_cost_node(vn, prevs)
123
- f = vn.prev = prevs[0]
124
- # puts "=> set_min_cost_node"
125
- # p f
126
-
127
- vn.cost = f.cost + @mtx.link_cost(f.right_id, vn.left_id)
116
+ def set_min_cost_node(vn, prevs)
117
+ f = vn.prev = prevs[0]
118
+ vn.cost = f.cost + @mtx.link_cost(f.right_id, vn.left_id)
128
119
 
129
- # puts "#{vn.cost} #{f.cost} #{f.right_id} #{vn.left_id} #{@mtx.link_cost(f.right_id, vn.left_id)} #{}"
130
-
131
- for i in 1..(prevs.size - 1)
132
- p = prevs[i]
133
- cost = p.cost + @mtx.link_cost(p.right_id, vn.left_id)
134
- if(cost < vn.cost)
135
- vn.cost = cost
136
- vn.prev = p
120
+ for i in 1..(prevs.size - 1)
121
+ p = prevs[i]
122
+ cost = p.cost + @mtx.link_cost(p.right_id, vn.left_id)
123
+ if(cost < vn.cost)
124
+ vn.cost = cost
125
+ vn.prev = p
126
+ end
137
127
  end
128
+ vn.cost += @wdc.cost(vn.word_id)
129
+ return vn
138
130
  end
139
- vn.cost += @wdc.cost(vn.word_id)
140
- return vn
141
131
  end
142
- end
143
132
 
144
133
  end
@@ -7,21 +7,41 @@ class String
7
7
  end
8
8
  end
9
9
 
10
+ #
11
+ #DoubleArrayのノード用の定数などが定義されているクラス
12
+ #
10
13
  class Node
14
+ #
15
+ #BASEノード用のメソッドが定義されているクラス
16
+ #
11
17
  class Base
18
+ #BASEノードに格納するID値をエンコードする
12
19
  def self.ids(nid)
13
20
  return (-1 * nid) - 1
14
21
  end
15
22
  end
16
23
 
24
+ #
25
+ #CHECKノード用の定数が定義されているクラス
26
+ #
17
27
  class Chck
28
+ #文字列の終端文字コード
29
+ #この文字はシステムにより予約されており、辞書内の形態素の表層形および解析対象テキストに含まれていた場合の動作は未定義
18
30
  TERMINATE_CODE = 0
31
+ #文字列の終端を表す文字定数
19
32
  TERMINATE_CHAR = TERMINATE_CODE.chr
33
+ #CHECKノードが未使用であることを示す文字コード
34
+ #この文字はシステムにより予約されており、辞書内の形態素の表層形および解析対象テキストに含まれていた場合の動作は未定義
20
35
  VACANT_CODE = 1
36
+ #使用可能な文字の最大値
21
37
  CODE_LIMIT = 0xffff
22
38
  end
23
39
  end
24
40
 
41
+ #
42
+ #文字列を文字のストリームとして扱うためのクラス
43
+ #* readメソッドで個々の文字を順に読み込み、文字列の終端に達した場合にはNode::Chck::TERMINATE_CODEが返される。
44
+ #
25
45
  class KeyStream
26
46
 
27
47
  def initialize(key, start = 0)
@@ -34,22 +54,21 @@ class KeyStream
34
54
  return rest.compare_to(ks.rest)
35
55
  end
36
56
 
57
+ #このメソッドは動作的には、rest().starts_with?(prefix.substring(beg, len))と等価。
58
+ #ほんの若干だが、パフォーマンスを改善するために導入。
59
+ #簡潔性のためになくしても良いかもしれない。
37
60
  def start_with(prefix, beg, len)
38
61
  s = @s
39
62
  c = @cur
40
63
  if @len - c < len
41
64
  return false
42
65
  end
43
- # puts "c = #{c} len = #{len}"
44
- # p s.unpack("U*")[c]
45
- # p [s.unpack("U*")[c]].pack("U*")
46
66
  word = s.unpack("U*")[c]
47
67
  if word.nil?
48
68
  return (prefix.slice(beg, len-beg) == nil)
49
69
  else
50
70
  [word].pack("U*").starts_with?(prefix.slice(beg, len-beg))
51
71
  end
52
- # return [s.unpack("U*")[c]].pack("U*").starts_with?(prefix.slice(beg, len-beg))
53
72
  end
54
73
 
55
74
  def rest
@@ -57,32 +76,28 @@ class KeyStream
57
76
  end
58
77
 
59
78
  def read
60
- # puts "CUR=#{@cur}"
61
79
 
62
80
  if eos?
63
- # puts "EOS!!"
64
81
  return Node::Chck::TERMINATE_CODE
65
82
  else
66
83
  r = @s.unpack("U*")[@cur]
67
- # puts [r].pack("U*").tosjis
68
84
  result = [r].pack("U*")
69
- # result = @s.unpack("U*")[@cur]
70
85
  @cur += 1
71
86
  return r
72
- # p = @cur
73
- # @cur += 1
74
- # return @s[p]
75
87
  end
76
88
  end
77
89
 
78
90
  def eos?
79
- # puts "eos? #{@cur} == #{@len}"
80
91
  return (@cur == @len) ? true : false
81
92
  end
82
93
  end
83
94
 
95
+ #
84
96
  # DoubleArray検索用のクラス
97
+ #
85
98
  class Searcher
99
+ #保存されているDoubleArrayを読み込んで、このクラスのインスタンスを作成する
100
+ #path:: DoubleArrayが保存されているファイルのパス
86
101
  def initialize(path)
87
102
  fmis = FileMappedInputStream.new(path)
88
103
  node_size = fmis.get_int()
@@ -94,20 +109,18 @@ class Searcher
94
109
  @lens = fmis.get_short_array(tind_size)
95
110
  @chck = fmis.get_char_array(node_size)
96
111
  @tail = fmis.get_string(tail_size)
97
-
98
- #p @begs[0]
99
- #p @base[0]
100
- #p @lens[0]
101
- #print @tail.tosjis
102
- #print @tail[0].tosjis
103
-
104
112
  fmis.close
105
113
  end
106
114
 
115
+ #DoubleArrayに格納されているキーの数を返却
116
+ #return:: DoubleArrayに格納されているキーの数
107
117
  def size
108
118
  return @key_set_size
109
119
  end
110
120
 
121
+ #キーを検索する
122
+ #key:: 検索対象のキー文字列
123
+ #return:: キーが見つかった場合はそのIDを、見つからなかった場合は-1を返す
111
124
  def search(key)
112
125
  base = @base
113
126
  chck = @chck
@@ -130,6 +143,11 @@ class Searcher
130
143
  end
131
144
  end
132
145
 
146
+ #common-prefix検索を行う
147
+ #* 条件に一致するキーが見つかる度に、callback.callメソッドが呼び出される
148
+ #key:: 検索対象のキー文字列
149
+ #start:: 検索対象となるキー文字列の最初の添字
150
+ #callback:: 一致を検出した場合に呼び出されるコールバックメソッド
133
151
  def each_common_prefix(key, start, callback)
134
152
  base = @base
135
153
  chck = @chck
@@ -137,48 +155,29 @@ class Searcher
137
155
  offset = -1
138
156
  kin = KeyStream.new(key, start)
139
157
 
140
- # puts "each_common_prefix"
141
158
  while true
142
159
  code = kin.read
143
160
  offset += 1
144
161
  terminal_index = node
145
- # terminal_index = node + Node::Chck::TERMINATE_CODE
146
- #puts "code #{code.tosjis}"
147
162
 
148
163
  if(chck[terminal_index] == Node::Chck::TERMINATE_CODE)
149
164
  callback.call(start, offset, Node::Base.ids(base[terminal_index]))
150
165
 
151
- # puts "code -> #{code} #{Node::Chck::TERMINATE_CHAR}"
152
-
153
166
  if(code == Node::Chck::TERMINATE_CODE)
154
- # puts code
155
- # puts "(1)"
156
167
  return
157
168
  end
158
169
  end
159
170
 
160
- # TODO
161
- #puts "code #{code.tosjis}"
162
- # p code
163
171
  idx = node + code
164
172
  node = base[idx]
165
173
 
166
- # code = [code].pack('U*')
167
-
168
174
  if(chck[idx] == code)
169
175
  if(node >= 0)
170
176
  next
171
177
  else
172
- # id = Node.Base.ids(node)
173
- # if(kin.start_with(@tail, @begs[id], lens[id]))
174
- # callback.call(start, offset+@lens[id]+1, id)
175
- # end
176
-
177
178
  call_if_key_including(kin, node, start, offset, callback)
178
179
  end
179
180
  end
180
- # puts code
181
- # puts "(2)"
182
181
  return
183
182
  end
184
183
  end
@@ -186,7 +185,6 @@ class Searcher
186
185
  private
187
186
 
188
187
  def call_if_key_including(kin, node, start, offset, callback)
189
- # puts "call_if_key_including"
190
188
  node_id = Node::Base.ids(node)
191
189
  if(kin.start_with(@tail, @begs[node_id], @lens[node_id]))
192
190
  callback.call(start, offset + @lens[node_id] + 1, node_id)
@@ -1,22 +1,31 @@
1
- # ユーティリティ
1
+ # ファイルユーティリティ
2
2
 
3
+ #
4
+ #=== ファイルにマッピングされた入力ストリーム
5
+ # ファイルからバイナリデータを取得する場合、必ずこのクラスが使用される。
6
+ #
3
7
  class FileMappedInputStream
8
+ # 入力ストリームの初期化
9
+ # path:: 入力ファイルのパス
4
10
  def initialize(path)
5
11
  @path = path
6
12
  @cur = 0
7
13
  @file = open(path, "r+b")
8
- # @file.binmode
9
14
  end
10
15
 
16
+ # int値で読み取り
11
17
  def get_int()
12
18
  return @file.read(4).unpack("i*")[0]
13
19
  end
14
20
 
21
+ # int配列で読み取り
22
+ # count:: 読み取りカウント
15
23
  def get_int_array(count)
16
- # return map(count * 4).unpack("i*")
17
24
  return @file.read(count * 4).unpack("i*")
18
25
  end
19
26
 
27
+ # int配列で読み取り
28
+ # path:: 入力ファイルのパス
20
29
  def self.get_int_array(path)
21
30
  fmis = FileMappedInputStream.new(path)
22
31
  array = fmis.get_int_array((File::stat(path).size)/4)
@@ -24,22 +33,26 @@ class FileMappedInputStream
24
33
  return array
25
34
  end
26
35
 
36
+ # short配列で読み取り
37
+ # count:: 読み取りカウント
27
38
  def get_short_array(count)
28
- # return map(count * 2).unpack("s*")
29
39
  return @file.read(count * 2).unpack("s*")
30
40
  end
31
41
 
42
+ # char配列で読み取り
43
+ # count:: 読み取りカウント
32
44
  def get_char_array(count)
33
- # return map(count * 2).unpack("S!*")
34
45
  return @file.read(count * 2).unpack("S!*")
35
46
  end
36
47
 
48
+ # stringで読み取り
49
+ # count:: 読み取りカウント
37
50
  def get_string(count)
38
- # return map(count * 2)
39
- # puts "read count = #{count}"
40
51
  return @file.read(count * 2)
41
52
  end
42
53
 
54
+ # stringで読み取り
55
+ # path:: 入力ファイル
43
56
  def self.get_string(path)
44
57
  fmis = FileMappedInputStream.new(path)
45
58
  str = fmis.get_string((File::stat(path).size)/2)
@@ -48,14 +61,19 @@ class FileMappedInputStream
48
61
  return str
49
62
  end
50
63
 
64
+ # 入力ファイルのサイズを返却する
51
65
  def size
52
66
  return File::stat(@path).size
53
67
  end
54
68
 
69
+ # 入力ストリームを閉じる
70
+ #* newした場合、必ずcloseを呼ぶこと
55
71
  def close
56
72
  @file.close
57
73
  end
58
74
 
75
+ # char配列で読み取り
76
+ # path:: 入力ファイル
59
77
  def self.get_char_array(path)
60
78
  fmis = FileMappedInputStream.new(path)
61
79
  array = fmis.get_char_array(fmis.size / 2)
@@ -65,10 +83,11 @@ class FileMappedInputStream
65
83
 
66
84
  private
67
85
 
68
- def __map(size)
86
+ # ファイルマップ
87
+ #* 現在、不使用
88
+ def map(size)
69
89
  @file.pos = @cur
70
90
  @cur += size
71
91
  return @file.read(size)
72
92
  end
73
93
  end
74
-
@@ -1,6 +1,6 @@
1
1
  require 'rubygems'
2
2
  require 'igo-ruby'
3
- tagger = Igo::Tagger.new('../ipadic')
3
+ tagger = Igo::Tagger.new('../../ipadic')
4
4
  t = tagger.parse('吾輩は猫である。名前はまだ無い。')
5
5
  t.each{|m|
6
6
  puts "#{m.surface} #{m.feature} #{m.start}"
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: igo-ruby
3
3
  version: !ruby/object:Gem::Version
4
- hash: 27
4
+ hash: 25
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 1
9
- - 0
10
- version: 0.1.0
9
+ - 1
10
+ version: 0.1.1
11
11
  platform: ruby
12
12
  authors:
13
13
  - K.Nishi
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-12-11 00:00:00 +09:00
18
+ date: 2010-12-12 00:00:00 +09:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -80,7 +80,7 @@ dependencies:
80
80
  name: rcov
81
81
  requirement: *id004
82
82
  type: :development
83
- description: Ruby port of Igo Japanese morphological analyzer.
83
+ 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
84
  email: 24signals@gmail.com
85
85
  executables: []
86
86
 
@@ -109,8 +109,10 @@ homepage: http://github.com/kyow/igo-ruby
109
109
  licenses:
110
110
  - MIT
111
111
  post_install_message:
112
- rdoc_options: []
113
-
112
+ rdoc_options:
113
+ - -c UTF-8
114
+ - -S
115
+ - -U
114
116
  require_paths:
115
117
  - lib
116
118
  required_ruby_version: !ruby/object:Gem::Requirement