tsukasaoishi-kaerukeyword 1.0.1 → 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (4) hide show
  1. data/History.txt +4 -0
  2. data/Rakefile +1 -1
  3. data/lib/kaerukeyword.rb +194 -26
  4. metadata +5 -4
@@ -7,3 +7,7 @@
7
7
 
8
8
  * 1 minor enhancement:
9
9
  * move to GitHub from Rubyforge
10
+
11
+ == 1.0.2 2009-09-27
12
+ * 1 minor enhancement:
13
+ * bug fix.
data/Rakefile CHANGED
@@ -4,7 +4,7 @@ require File.dirname(__FILE__) + '/lib/kaerukeyword'
4
4
  # Generate all the Rake tasks
5
5
  # Run 'rake -T' to see list of generated tasks (from gem root directory)
6
6
  $hoe = Hoe.new('kaerukeyword', Kaerukeyword::VERSION) do |p|
7
- p.developer('FIXME full name', 'FIXME email')
7
+ p.developer('Tsukasa OISHI', 'tsukasa.oishi@gmail.com')
8
8
  p.changes = p.paragraphs_of("History.txt", 0..1).join("\n\n")
9
9
  p.rubyforge_name = p.name # TODO this is default value
10
10
  p.extra_dev_deps = [
@@ -33,47 +33,215 @@ $:.unshift(File.dirname(__FILE__)) unless
33
33
  # http://www.kaeruspoon.net
34
34
  #
35
35
  #
36
+ require 'forwardable'
37
+
36
38
  class Kaerukeyword
37
- VERSION = '1.0.1'
39
+ extend Forwardable
40
+
41
+ VERSION = '1.0.2'
42
+
43
+ # 委譲するメソッド
44
+ def_delegators :@logic, :add, :search, :match
38
45
 
39
- def initialize(key_array = nil)
40
- @tree = {}
41
- key_array.each {|k| add(k)} if key_array.is_a?(Array)
46
+ #
47
+ # コンストラクタ
48
+ # 第2引数でデータ構造を選択できる
49
+ #
50
+ def initialize(key_array = nil, logic = :hash_tree)
51
+ @logic =
52
+ case logic
53
+ when :hash_tree
54
+ HashTree.new(key_array)
55
+ when :double_array
56
+ raise NotSupportError, "double array will support, but doesn't yet"
57
+ DoubleArray.new(key_array)
58
+ else
59
+ raise LogicError, "you have to select logic"
60
+ end
42
61
  end
43
62
 
44
- def add(key)
45
- now = @tree
46
- key.split(//).each do |c|
47
- now[c] = {} unless now.has_key? c
48
- now = now[c]
49
- end
50
- now[:end] = key
63
+ #
64
+ # ハッシュ木からダブル配列への変換
65
+ #
66
+ def double_array!
67
+ raise NotSupportError, "double array will support, but doesn't yet"
68
+ raise LogicError, "already double array" if @logic.is_a?(DoubleArray)
69
+ old_logic = @logic
70
+ hash_tree = old_logic.tree
71
+
72
+ @logic = DoubleArray.new
73
+ @logic.construct_array(hash_tree, 0)
74
+
75
+ old_logic = nil
76
+ hash_tree = nil
77
+ GC.start
78
+ true
51
79
  end
80
+
52
81
  alias :<< :add
82
+
83
+ #
84
+ # ダブル配列
85
+ #
86
+ class DoubleArray
87
+ def initialize(key_array = nil)
88
+ hash_tree = HashTree.new(key_array)
89
+ @base = [1]
90
+ @check = [0]
91
+ @code = {"end" => 1}
92
+ construct_array(hash_tree.tree, 0) if key_array.is_a?(Array)
93
+ hash_tree = nil
94
+ GC.start
95
+ end
96
+
97
+ #
98
+ # 未サポート
99
+ #
100
+ def add(key)
101
+ raise NotSupportError, "you don't add keyword after initilize."
102
+ end
53
103
 
54
- def search(text)
55
- list = []
56
- word = ""
57
- now = @tree
58
- text.split(//).each do |c|
59
- unless now.has_key? c
60
- unless word.empty?
61
- list << word
104
+ #
105
+ # 検索
106
+ #
107
+ def search(text)
108
+ list = []
109
+ word = ""
110
+ buffer = ""
111
+ now_x = 0
112
+
113
+ text.scan(/./).each do |c|
114
+ code = @code[c]
115
+ base = @base[now_x]
116
+ if code && @base[base + code] && @check[base + code] == now_x
117
+ now_x = base + code
118
+ buffer << c
119
+ if @base[@base[now_x] + @code["end"]].to_i < 0 && @check[@base[now_x] + @code["end"]] == now_x
120
+ word = buffer.dup
121
+ end
122
+ else
123
+ list << word unless word.empty?
62
124
  word = ""
125
+ buffer = ""
126
+ now_x = 0
63
127
  end
64
- now = @tree
65
128
  end
66
129
 
67
- if now.has_key? c
68
- now = now[c]
69
- word = now[:end] if now[:end]
130
+ list << word unless word.empty?
131
+ list
132
+ end
133
+
134
+ #
135
+ # ハッシュ木からBC配列を構築
136
+ #
137
+ def construct_array(hash_tree, now_x)
138
+ x_hash = {}
139
+ chars = hash_tree.keys.sort_by{|k| k.to_s}
140
+ code_set(chars)
141
+ @base[now_x] = base = get_base(chars, now_x)
142
+
143
+ chars.each do |c|
144
+ @check[base + @code[c]] = now_x
145
+ if c == "end"
146
+ @base[base + @code[c]] = -base
147
+ else
148
+ @base[base + @code[c]] = base
149
+ x_hash[c] = base + @code[c]
150
+ end
70
151
  end
152
+
153
+ x_hash.each {|c, x| construct_array(hash_tree[c], x)}
71
154
  end
72
155
 
73
- unless word.empty?
74
- list << word
156
+ private
157
+
158
+ #
159
+ # コード配列の定義
160
+ #
161
+ def code_set(chars)
162
+ chars.each {|c| @code[c] = @code.size + 1 unless @code.has_key?(c)}
75
163
  end
76
164
 
77
- list
165
+ #
166
+ # 節のbase値の決定
167
+ #
168
+ def get_base(chars, now_x)
169
+ base = @base[now_x]
170
+ chars.each do |c|
171
+ if @check[base + @code[c]] && @check[base + @code[c]] != now_x
172
+ base += 1
173
+ retry
174
+ end
175
+ end
176
+ base
177
+ end
78
178
  end
179
+
180
+ class HashTree
181
+ END_TAG = "en"
182
+
183
+ attr_accessor :tree
184
+
185
+ def initialize(key_array = [])
186
+ @nodes = {}
187
+ make_tree(key_array)
188
+ end
189
+
190
+ def make_tree(key_array)
191
+ key_array.each{|key| add(key)}
192
+ end
193
+
194
+ #
195
+ # キーワードの追加
196
+ #
197
+ def add(key)
198
+ cur = @nodes
199
+ key.scan(/./).each do |c|
200
+ cur[c] ||= {}
201
+ cur = cur[c]
202
+ end
203
+ cur[END_TAG] = true
204
+ end
205
+
206
+ def search(text)
207
+ list = []
208
+ word = ""
209
+ buffer = ""
210
+ cur = @nodes
211
+ i = 0
212
+ hit_i = nil
213
+ str = text.scan(/./)
214
+
215
+ loop do
216
+ break unless c = str[i]
217
+
218
+ unless cur.has_key?(c)
219
+ if word.empty?
220
+ i = (hit_i || i) + 1
221
+ else
222
+ list << word
223
+ i = hit_i + word.scan(/./).size
224
+ word = ""
225
+ end
226
+ hit_i = nil
227
+ buffer = ""
228
+ cur = @nodes
229
+ end
230
+
231
+ if cur.has_key?(c)
232
+ cur = cur[c]
233
+ buffer << c
234
+ word = buffer.dup if cur.has_key?(END_TAG)
235
+ hit_i = i unless hit_i
236
+ end
237
+ i += 1
238
+ end
239
+
240
+ list << word unless word.empty?
241
+ list
242
+ end
243
+ end
244
+
245
+ class LogicError < StandardError; end
246
+ class NotSupportError < StandardError; end
79
247
  end
metadata CHANGED
@@ -1,10 +1,10 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tsukasaoishi-kaerukeyword
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 1.0.2
5
5
  platform: ruby
6
6
  authors:
7
- - FIXME full name
7
+ - Tsukasa OISHI
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
@@ -34,7 +34,7 @@ dependencies:
34
34
  version:
35
35
  description: "KaeruKeyword \xE3\x81\xAF\xE7\x99\xBB\xE9\x8C\xB2\xE3\x81\x95\xE3\x82\x8C\xE3\x81\x9F\xE3\x82\xAD\xE3\x83\xBC\xE3\x83\xAF\xE3\x83\xBC\xE3\x83\x89\xE3\x81\x8C\xE6\x96\x87\xE4\xB8\xAD\xE3\x81\xAB\xE5\xAD\x98\xE5\x9C\xA8 \xE3\x81\x99\xE3\x82\x8B\xE3\x81\x8B\xE3\x81\xA9\xE3\x81\x86\xE3\x81\x8B\xE3\x82\x92\xE8\xAA\xBF\xE3\x81\xB9\xE3\x82\x8B\xE3\x81\x93\xE3\x81\xA8\xE3\x81\x8C\xE3\x81\xA7\xE3\x81\x8D\xE3\x81\xBE\xE3\x81\x99\xE3\x80\x82 \xE3\x82\xA4\xE3\x83\xB3\xE3\x82\xB9\xE3\x82\xBF\xE3\x83\xB3\xE3\x82\xB9\xE3\x81\xAE\xE4\xBD\x9C\xE6\x88\x90\xE6\x99\x82\xE3\x81\xAB\xE3\x82\xAD\xE3\x83\xBC\xE3\x83\xAF\xE3\x83\xBC\xE3\x83\x89\xE3\x82\x92\xE7\x99\xBB\xE9\x8C\xB2\xE3\x81\xA7\xE3\x81\x8D\xE3\x81\xBE\xE3\x81\x99\xE3\x80\x82 keywords = KaeruKeyword.new([\"Ruby\", \"Rails\"]) \xE3\x81\x82\xE3\x81\xA8\xE3\x81\x8B\xE3\x82\x89\xE3\x82\xAD\xE3\x83\xBC\xE3\x83\xAF\xE3\x83\xBC\xE3\x83\x89\xE3\x82\x92\xE8\xBF\xBD\xE5\x8A\xA0\xE3\x81\x99\xE3\x82\x8B\xE3\x81\x93\xE3\x81\xA8\xE3\x82\x82\xE3\x81\xA7\xE3\x81\x8D\xE3\x81\xBE\xE3\x81\x99\xE3\x80\x82 keywords << \"Tsukasa\" search\xE3\x83\xA1\xE3\x82\xBD\xE3\x83\x83\xE3\x83\x89\xE3\x81\xA7\xE6\x96\x87\xE4\xB8\xAD\xE3\x81\x8B\xE3\x82\x89\xE3\x82\xAD\xE3\x83\xBC\xE3\x83\xAF\xE3\x83\xBC\xE3\x83\x89\xE3\x82\x92\xE6\x8E\xA2\xE3\x81\x97\xE5\x87\xBA\xE3\x81\x97\xE3\x81\xBE\xE3\x81\x99\xE3\x80\x82 \xE3\x82\xAD\xE3\x83\xBC\xE3\x83\xAF\xE3\x83\xBC\xE3\x83\x89\xE3\x81\x8C\xE8\xA6\x8B\xE3\x81\xA4\xE3\x81\x8B\xE3\x81\xA3\xE3\x81\x9F\xE3\x81\xA8\xE3\x81\x8D\xE3\x81\xAF\xE3\x80\x81\xE3\x81\x9D\xE3\x81\xAE\xE3\x82\xAD\xE3\x83\xBC\xE3\x83\xAF\xE3\x83\xBC\xE3\x83\x89\xE3\x82\x92 \xE5\x90\xAB\xE3\x82\x81\xE3\x81\x9F\xE9\x85\x8D\xE5\x88\x97\xE3\x82\x92\xE8\xBF\x94\xE3\x81\x97\xE3\x81\xBE\xE3\x81\x99\xE3\x80\x82 keywords.search(\"I Love Ruby\") #=> [\"Ruby\"]"
36
36
  email:
37
- - FIXME email
37
+ - tsukasa.oishi@gmail.com
38
38
  executables: []
39
39
 
40
40
  extensions: []
@@ -51,6 +51,7 @@ files:
51
51
  - lib/kaerukeyword.rb
52
52
  has_rdoc: true
53
53
  homepage:
54
+ licenses:
54
55
  post_install_message:
55
56
  rdoc_options:
56
57
  - --main
@@ -72,7 +73,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
72
73
  requirements: []
73
74
 
74
75
  rubyforge_project: kaerukeyword
75
- rubygems_version: 1.2.0
76
+ rubygems_version: 1.3.5
76
77
  signing_key:
77
78
  specification_version: 2
78
79
  summary: "KaeruKeyword \xE3\x81\xAF\xE7\x99\xBB\xE9\x8C\xB2\xE3\x81\x95\xE3\x82\x8C\xE3\x81\x9F\xE3\x82\xAD\xE3\x83\xBC\xE3\x83\xAF\xE3\x83\xBC\xE3\x83\x89\xE3\x81\x8C\xE6\x96\x87\xE4\xB8\xAD\xE3\x81\xAB\xE5\xAD\x98\xE5\x9C\xA8 \xE3\x81\x99\xE3\x82\x8B\xE3\x81\x8B\xE3\x81\xA9\xE3\x81\x86\xE3\x81\x8B\xE3\x82\x92\xE8\xAA\xBF\xE3\x81\xB9\xE3\x82\x8B\xE3\x81\x93\xE3\x81\xA8\xE3\x81\x8C\xE3\x81\xA7\xE3\x81\x8D\xE3\x81\xBE\xE3\x81\x99\xE3\x80\x82 \xE3\x82\xA4\xE3\x83\xB3\xE3\x82\xB9\xE3\x82\xBF\xE3\x83\xB3\xE3\x82\xB9\xE3\x81\xAE\xE4\xBD\x9C\xE6\x88\x90\xE6\x99\x82\xE3\x81\xAB\xE3\x82\xAD\xE3\x83\xBC\xE3\x83\xAF\xE3\x83\xBC\xE3\x83\x89\xE3\x82\x92\xE7\x99\xBB\xE9\x8C\xB2\xE3\x81\xA7\xE3\x81\x8D\xE3\x81\xBE\xE3\x81\x99\xE3\x80\x82 keywords = KaeruKeyword.new([\"Ruby\", \"Rails\"]) \xE3\x81\x82\xE3\x81\xA8\xE3\x81\x8B\xE3\x82\x89\xE3\x82\xAD\xE3\x83\xBC\xE3\x83\xAF\xE3\x83\xBC\xE3\x83\x89\xE3\x82\x92\xE8\xBF\xBD\xE5\x8A\xA0\xE3\x81\x99\xE3\x82\x8B\xE3\x81\x93\xE3\x81\xA8\xE3\x82\x82\xE3\x81\xA7\xE3\x81\x8D\xE3\x81\xBE\xE3\x81\x99\xE3\x80\x82 keywords << \"Tsukasa\" search\xE3\x83\xA1\xE3\x82\xBD\xE3\x83\x83\xE3\x83\x89\xE3\x81\xA7\xE6\x96\x87\xE4\xB8\xAD\xE3\x81\x8B\xE3\x82\x89\xE3\x82\xAD\xE3\x83\xBC\xE3\x83\xAF\xE3\x83\xBC\xE3\x83\x89\xE3\x82\x92\xE6\x8E\xA2\xE3\x81\x97\xE5\x87\xBA\xE3\x81\x97\xE3\x81\xBE\xE3\x81\x99\xE3\x80\x82 \xE3\x82\xAD\xE3\x83\xBC\xE3\x83\xAF\xE3\x83\xBC\xE3\x83\x89\xE3\x81\x8C\xE8\xA6\x8B\xE3\x81\xA4\xE3\x81\x8B\xE3\x81\xA3\xE3\x81\x9F\xE3\x81\xA8\xE3\x81\x8D\xE3\x81\xAF\xE3\x80\x81\xE3\x81\x9D\xE3\x81\xAE\xE3\x82\xAD\xE3\x83\xBC\xE3\x83\xAF\xE3\x83\xBC\xE3\x83\x89\xE3\x82\x92 \xE5\x90\xAB\xE3\x82\x81\xE3\x81\x9F\xE9\x85\x8D\xE5\x88\x97\xE3\x82\x92\xE8\xBF\x94\xE3\x81\x97\xE3\x81\xBE\xE3\x81\x99\xE3\x80\x82 keywords.search(\"I Love Ruby\") #=> [\"Ruby\"]"