re_expand 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gemtest ADDED
File without changes
data/History.txt ADDED
@@ -0,0 +1,4 @@
1
+ === 0.0.1 2012-04-30
2
+
3
+ * 1 major enhancement:
4
+ * Initial release
data/Manifest.txt ADDED
@@ -0,0 +1,20 @@
1
+ History.txt
2
+ Manifest.txt
3
+ PostInstall.txt
4
+ README.rdoc
5
+ Rakefile
6
+ lib/re_expand.rb
7
+ lib/Generator.rb
8
+ lib/Node.rb
9
+ lib/Asearch.rb
10
+ lib/Scanner.rb
11
+ script/console
12
+ script/destroy
13
+ script/generate
14
+ test/test_helper.rb
15
+ test/test_re_expand.rb
16
+ test/test_asearch.rb
17
+ test/test_generator.rb
18
+ test/test_re_expand.rb
19
+ test/test_scanner.rb
20
+
data/PostInstall.txt ADDED
@@ -0,0 +1,7 @@
1
+
2
+ For more information on re_expand, see http://re_expand.rubyforge.org
3
+
4
+ NOTE: Change this information in PostInstall.txt
5
+ You can also delete it if you don't want it.
6
+
7
+
data/README.rdoc ADDED
@@ -0,0 +1,43 @@
1
+ = re_expand
2
+
3
+ * http://github.com/masui/expand-ruby
4
+
5
+ == DESCRIPTION:
6
+
7
+ Generates all the text strings which match the given regexp.
8
+ If a filter pattern is given, the output is filtered by the pattern.
9
+
10
+ == SYNOPSIS:
11
+
12
+ require 're_expand'
13
+ "test (a|b|c)".expand { |s|
14
+ puts s
15
+ }
16
+ # "test a", "test b", ...
17
+ "(a|b)(1|2)".expand
18
+ # => ['a1', 'a2', 'b1', 'b2']
19
+
20
+ == LICENSE:
21
+
22
+ (The MIT License)
23
+
24
+ Copyright (c) 2012 Toshiyuki Masui
25
+
26
+ Permission is hereby granted, free of charge, to any person obtaining
27
+ a copy of this software and associated documentation files (the
28
+ 'Software'), to deal in the Software without restriction, including
29
+ without limitation the rights to use, copy, modify, merge, publish,
30
+ distribute, sublicense, and/or sell copies of the Software, and to
31
+ permit persons to whom the Software is furnished to do so, subject to
32
+ the following conditions:
33
+
34
+ The above copyright notice and this permission notice shall be
35
+ included in all copies or substantial portions of the Software.
36
+
37
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
38
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
39
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
40
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
41
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
42
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
43
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,26 @@
1
+ require 'rubygems'
2
+ gem 'hoe', '>= 2.1.0'
3
+ require 'hoe'
4
+ require 'fileutils'
5
+ require './lib/re_expand'
6
+
7
+ Hoe.plugin :newgem
8
+ # Hoe.plugin :website
9
+ # Hoe.plugin :cucumberfeatures
10
+
11
+ # Generate all the Rake tasks
12
+ # Run 'rake -T' to see list of generated tasks (from gem root directory)
13
+ $hoe = Hoe.spec 're_expand' do
14
+ self.developer 'Toshiyuki Masui', 'masui@pitecan.com'
15
+ self.post_install_message = 'PostInstall.txt' # TODO remove if post-install message not required
16
+ self.rubyforge_name = self.name # TODO this is default value
17
+ # self.extra_deps = [['activesupport','>= 2.0.2']]
18
+
19
+ end
20
+
21
+ require 'newgem/tasks'
22
+ Dir['tasks/**/*.rake'].each { |t| load t }
23
+
24
+ # TODO - want other tests/tasks run by default? Add them to the list
25
+ # remove_task :default
26
+ # task :default => [:spec, :features]
data/lib/Asearch.rb ADDED
@@ -0,0 +1,105 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Asearch.rb
3
+ #
4
+ # Created by Toshiyuki Masui on 11/04/16.
5
+ # Copyright 2011 Pitecan Systems. All rights reserved.
6
+ #
7
+ # a = Asearch.new('abcde')
8
+ # a.match('abcde') => true
9
+ # a.match('abXcde',1) => true
10
+ #
11
+ # a = Asearch.new('abcde')
12
+ # initstate = a.initstate
13
+ # laststate = a.state(initstate,'abcde')
14
+ # laststate[0] & a.acceptpat => non-zero value
15
+ #
16
+
17
+ class Asearch
18
+ INITPAT = 0x80000000
19
+ MAXCHAR = 0x100
20
+
21
+ def isupper(c)
22
+ c >= 0x41 && c <= 0x5a
23
+ end
24
+
25
+ def islower(c)
26
+ c >= 0x61 && c <= 0x7a
27
+ end
28
+
29
+ def tolower(c)
30
+ c + 0x20
31
+ end
32
+
33
+ def toupper(c)
34
+ c - 0x20
35
+ end
36
+
37
+ def initialize(pat)
38
+ @shiftpat = []
39
+ @epsilon = 0
40
+ @acceptpat = 0
41
+ mask = INITPAT
42
+ (0...MAXCHAR).each { |c|
43
+ @shiftpat[c] = 0
44
+ }
45
+ chars = pat.unpack("C*")
46
+ chars.each { |c|
47
+ if c == 0x20 then
48
+ @epsilon |= mask
49
+ else
50
+ @shiftpat[c] |= mask
51
+ @shiftpat[toupper(c)] |= mask if islower(c)
52
+ @shiftpat[tolower(c)] |= mask if isupper(c)
53
+ mask >>= 1
54
+ end
55
+ }
56
+ @acceptpat = mask
57
+ end
58
+
59
+ attr_reader :acceptpat
60
+
61
+ def bin(val)
62
+ s = "00000000000000000000000000000000000000000" + sprintf("%b",val)
63
+ s[-32,100]
64
+ end
65
+
66
+ #
67
+ # 状態stateからテキストstrを認識したときの状態変化
68
+ #
69
+ def state(state=nil,str='')
70
+ if state.nil? then
71
+ state = initstate
72
+ end
73
+ i0 = state[0]
74
+ i1 = state[1]
75
+ i2 = state[2]
76
+ i3 = state[3]
77
+ chars = str.unpack("C*")
78
+ chars.each { |c|
79
+ mask = @shiftpat[c]
80
+ i3 = (i3 & @epsilon) | ((i3 & mask) >> 1) | (i2 >> 1) | i2
81
+ i2 = (i2 & @epsilon) | ((i2 & mask) >> 1) | (i1 >> 1) | i1
82
+ i1 = (i1 & @epsilon) | ((i1 & mask) >> 1) | (i0 >> 1) | i0
83
+ i0 = (i0 & @epsilon) | ((i0 & mask) >> 1)
84
+ i1 |= (i0 >> 1)
85
+ i2 |= (i1 >> 1)
86
+ i3 |= (i2 >> 1)
87
+ }
88
+ #puts bin(i3)
89
+ #puts bin(i2)
90
+ #puts bin(i1)
91
+ #puts bin(i0)
92
+ #puts bin(acceptpat | INITPAT)
93
+ [i0, i1, i2, i3]
94
+ end
95
+
96
+ def initstate
97
+ [INITPAT, 0, 0, 0]
98
+ end
99
+
100
+ def match(str, ambig=0)
101
+ s = state(initstate,str)
102
+ s[ambig] & acceptpat != 0
103
+ end
104
+ end
105
+
data/lib/Generator.rb ADDED
@@ -0,0 +1,233 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Generator.rb
3
+ # ExpandHelpApp
4
+ #
5
+ # Created by Toshiyuki Masui on 2011/02/26.
6
+ # Copyright 2011 Pitecan Systems. All rights reserved.
7
+
8
+ #
9
+ # ( ( ) ) ( ( ) ( ( ) ) ( ) ) | ( ( ) )
10
+ # pars [1]
11
+ # [1,2]
12
+ # [3]
13
+ # [3,4]
14
+ # [3,5]
15
+
16
+ require 'Scanner'
17
+ require 'Node'
18
+ require 'Asearch'
19
+
20
+ class GenNode
21
+ def initialize(id, state=[], s="", substrings=[], accept=false)
22
+ @id = id
23
+ @s = s
24
+ @substrings = substrings
25
+ @accept = accept
26
+ @state = state
27
+ end
28
+
29
+ attr :id, true
30
+ attr :s, true
31
+ attr :substrings, true
32
+ attr :accept, true
33
+ attr :state, true
34
+ end
35
+
36
+ class Generator
37
+ def initialize(s = nil)
38
+ @s = (s ? [s] : [])
39
+ @matchedlist = []
40
+ @par = 0
41
+ @commands = []
42
+ end
43
+
44
+ def add(pat,command)
45
+ @s << pat
46
+ @commands << command
47
+ end
48
+
49
+ def delete
50
+ @s.pop
51
+ @commands.pop
52
+ end
53
+
54
+ #
55
+ # ルールを解析して状態遷移機械を作成し、patにマッチするもののリストを返す
56
+ #
57
+ def generate(pat, app = nil)
58
+ res = [[],[],[]] # 曖昧度0,1,2のマッチ結果
59
+ patterns = pat.split.map { |p| p.downcase }
60
+
61
+ @asearch = Asearch.new(pat)
62
+ scanner = Scanner.new(@s.join('|'))
63
+
64
+ # HelpDataで指定した状態遷移機械全体を生成
65
+ # (少し時間がかかる)
66
+ (startnode, endnode) = regexp(scanner,true) # top level
67
+
68
+ #
69
+ # 状態遷移機械からDepth-Firstで文字列を生成する
70
+ # n個のノードを経由して生成される状態の集合をlists[n]に入れる
71
+ # 生成しながらマッチングも計算する
72
+ #
73
+ lists = []
74
+ listed = [{},{},{}]
75
+ #
76
+ # 初期状態
77
+ #
78
+ list = []
79
+ list[0] = GenNode.new(startnode.id, @asearch.initstate)
80
+ lists[0] = list
81
+ #
82
+ (0..1000).each { |length|
83
+ break if app && app.inputPending
84
+ list = lists[length]
85
+ newlist = []
86
+ # puts "#{length} - #{list.length}"
87
+ list.each { |entry|
88
+ srcnode = Node.node(entry.id)
89
+ if list.length * srcnode.trans.length < 10000 then
90
+ srcnode.trans.each { |trans|
91
+ ss = entry.substrings.dup
92
+ srcnode.pars.each { |i|
93
+ ss[i-1] = ss[i-1].to_s + trans.arg
94
+ }
95
+ newstate = @asearch.state(entry.state, trans.str) # 新しいマッチング状態を計算してノードに保存
96
+ s = entry.s + trans.str
97
+ acceptno = trans.dest.accept
98
+ newlist << GenNode.new(trans.dest.id, newstate, s, ss, acceptno)
99
+ #
100
+ # この時点で、マッチしているかどうかをstateとacceptpatで判断できる
101
+ # マッチしてたら出力リストに加える
102
+ #
103
+ if acceptno then
104
+ maxambig = 2
105
+ (0..maxambig).each { |ambig|
106
+ if !listed[ambig][s] then
107
+ if (newstate[ambig] & @asearch.acceptpat) != 0 then # マッチ
108
+ maxambig = ambig if ambig < maxambig # 曖昧度0でマッチすれば曖昧度1の検索は不要
109
+ listed[ambig][s] = true
110
+ sslen = ss.length
111
+ if sslen > 0 then
112
+ # patstr = "(.*)\t" * (sslen-1) + "(.*)"
113
+ patstr = (["(.*)"] * sslen).join("\t")
114
+ /#{patstr}/ =~ ss.join("\t")
115
+ end
116
+ ## next if $1 == $2
117
+ # 'set date #{$2}' のような記述の$変数にsubstringの値を代入
118
+ File.open("/tmp/log","a"){ |f|
119
+ f.puts "#{s}-----" + eval('%('+@commands[acceptno]+')')
120
+ }
121
+ res[ambig] << [s, eval('%('+@commands[acceptno]+')')]
122
+ end
123
+ end
124
+ }
125
+ end
126
+ }
127
+ end
128
+ }
129
+ break if newlist.length == 0
130
+ lists << newlist
131
+ break if res[0].length > 100
132
+ }
133
+ [res[0], res[1], res[2]]
134
+ end
135
+
136
+ #
137
+ # 正規表現をパースして状態遷移機械を作る
138
+ #
139
+ private
140
+ # n1 n2
141
+ # +-->□.....□--+
142
+ # start / \ end
143
+ # □ --->□.....□---> □
144
+ # \ /
145
+ # +-->□.....□--+
146
+ #
147
+ def regexp(s,toplevel=false) # regcat { '|' regcat }
148
+ startnode = Node.new
149
+ endnode = Node.new
150
+ if toplevel then
151
+ @pars = []
152
+ @parno = 0
153
+ @ruleid = 0
154
+ end
155
+ startnode.pars = @pars
156
+ endnode.pars = @pars
157
+ (n1, n2) = regcat(s)
158
+ startnode.addTrans('',n1)
159
+ if toplevel then
160
+ n2.accept = @ruleid
161
+ end
162
+ n2.addTrans('',endnode)
163
+ while s.gettoken == '|' && s.nexttoken != '' do
164
+ if toplevel then
165
+ @pars = []
166
+ @parno = 0
167
+ @ruleid += 1
168
+ end
169
+ (n1, n2) = regcat(s)
170
+ startnode.addTrans('',n1)
171
+ if toplevel then
172
+ n2.accept = @ruleid
173
+ end
174
+ n2.addTrans('',endnode)
175
+ end
176
+ s.ungettoken
177
+ return [startnode, endnode]
178
+ end
179
+
180
+ def regcat(s) # regfactor { regfactor }
181
+ (startnode, endnode) = regfactor(s)
182
+ while s.gettoken !~ /^[\)\]\|]$/ && s.nexttoken != '' do
183
+ s.ungettoken
184
+ (n1, n2) = regfactor(s)
185
+ endnode.addTrans('',n1)
186
+ endnode = n2
187
+ end
188
+ s.ungettoken
189
+ return [startnode, endnode]
190
+ end
191
+
192
+ def regfactor(s) # regterm [ '?' | '+' | '*' ]
193
+ (startnode, endnode) = regterm(s)
194
+ t = s.gettoken
195
+ if t =~ /^[\?]$/ then
196
+ startnode.addTrans('',endnode)
197
+ elsif t =~ /^[\+]$/ then
198
+ endnode.addTrans('',startnode)
199
+ elsif t =~ /^[\*]$/ then
200
+ startnode.addTrans('',endnode)
201
+ endnode.addTrans('',startnode)
202
+ else
203
+ s.ungettoken
204
+ end
205
+ return [startnode,endnode]
206
+ end
207
+
208
+ def regterm(s) # '(' regexp ')' | token
209
+ t = s.gettoken
210
+ if t == '(' then
211
+ @parno += 1
212
+ @pars.push(@parno)
213
+ (n1, n2) = regexp(s)
214
+ n1.pars = @pars.dup
215
+ t = s.gettoken
216
+ if t == ')' then
217
+ @pars.pop
218
+ n2.pars = @pars.dup
219
+ return [n1, n2]
220
+ else
221
+ puts 'missing )'
222
+ exit
223
+ end
224
+ else
225
+ startnode = Node.new
226
+ startnode.pars = @pars.dup
227
+ endnode = Node.new
228
+ endnode.pars = @pars.dup
229
+ startnode.addTrans(t,endnode)
230
+ return [startnode, endnode]
231
+ end
232
+ end
233
+ end
data/lib/Node.rb ADDED
@@ -0,0 +1,63 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ # ノードとノード間遷移
4
+ #
5
+ # (self) pat dest
6
+ # ■ ----------> □
7
+ # ----------> □
8
+ # ----------> □
9
+ #
10
+
11
+ class Trans
12
+ def initialize(pat,dest)
13
+ # pat にマッチしたら dest に遷移
14
+ @pat = pat
15
+ @dest = dest
16
+ end
17
+
18
+ attr_reader :pat, :dest
19
+
20
+ def str
21
+ @pat.split(/\t/)[0].to_s
22
+ end
23
+
24
+ def arg
25
+ if @pat =~ /^(.*)\t(.*)$/ then
26
+ return $2
27
+ else
28
+ return @pat
29
+ end
30
+ end
31
+ end
32
+
33
+ class Node
34
+ @@id = 1
35
+ @@nodes = {}
36
+
37
+ def initialize
38
+ @accept = nil
39
+ @trans = []
40
+ @id = @@id
41
+ @@nodes[@id] = self
42
+ @@id += 1
43
+ @pars = []
44
+ end
45
+
46
+ attr_reader :id
47
+ attr_reader :trans
48
+ attr :accept, true
49
+ attr :pars, true
50
+
51
+ def addTrans(pat,dest)
52
+ t = Trans.new(pat,dest)
53
+ @trans << t
54
+ end
55
+
56
+ def Node.node(id) # ノードidからノードを取得
57
+ @@nodes[id.to_i]
58
+ end
59
+
60
+ def Node.nodes
61
+ @@nodes.values
62
+ end
63
+ end
data/lib/Scanner.rb ADDED
@@ -0,0 +1,59 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ # 文字列から1トークンずつ取得
4
+ #
5
+
6
+ $KCODE = 'utf8'
7
+
8
+ class Scanner
9
+ def initialize(s)
10
+ @s = s
11
+ @a = s.split(//)
12
+ @p = 0
13
+ @t = ''
14
+ @u = ''
15
+ end
16
+
17
+ def gettoken
18
+ if @u != '' then
19
+ @t = @u
20
+ @u = ''
21
+ return @t
22
+ end
23
+ if @p >= @a.length then
24
+ @t = ''
25
+ return ''
26
+ end
27
+ @t = @a[@p]
28
+ if @t =~ /^[\(\|\)\*\?\[\]]$/ then
29
+ @p += 1
30
+ return @t
31
+ elsif @t == '\\' then
32
+ @p += 1
33
+ @t = @a[@p]
34
+ @t = "\n" if @t == 'n'
35
+ @t = "\t" if @t == 't'
36
+ @p += 1
37
+ return @t
38
+ else
39
+ @p += 1
40
+ while @p < @a.length && @a[@p] !~ /^[\(\|\)\*\+\?\[\]\\]$/ do
41
+ @t += @a[@p]
42
+ @p += 1
43
+ end
44
+ return @t
45
+ end
46
+ end
47
+
48
+ def ungettoken
49
+ if @u == '' then
50
+ @u = @t
51
+ else
52
+ puts "Can't ungettoken(#{token})"
53
+ end
54
+ end
55
+
56
+ def nexttoken
57
+ return @t
58
+ end
59
+ end
data/lib/re_expand.rb ADDED
@@ -0,0 +1,47 @@
1
+ # -*- coding: utf-8 -*-
2
+ $:.unshift(File.dirname(__FILE__)) unless
3
+ $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
4
+
5
+ module ReExpand
6
+ VERSION = '0.0.1'
7
+ end
8
+
9
+ require 'Generator'
10
+ require 'Node'
11
+ require 'Asearch'
12
+ require 'Scanner'
13
+
14
+ class String
15
+ # ExpandHelp用のライブラリを利用
16
+ def expand(filterpat=' ')
17
+ g = Generator.new
18
+ g.add(self,'')
19
+ strings = []
20
+ if filterpat.class == String then
21
+ matched = g.generate(filterpat)
22
+ res = matched[0].length > 0 ? matched[0] : matched[1].length > 0 ? matched[1] : matched[2]
23
+ strings = res.collect { |r|
24
+ r[0]
25
+ }
26
+ elsif
27
+ matched = g.generate(' ')
28
+ strings = matched[0].collect { |r|
29
+ r[0]
30
+ }
31
+ if filterpat.class == Regexp then
32
+ strings = strings.find_all { |s|
33
+ filterpat.match(s)
34
+ }
35
+ end
36
+ end
37
+
38
+ if block_given? then
39
+ strings.each { |string|
40
+ yield string
41
+ }
42
+ else
43
+ strings
44
+ end
45
+ end
46
+ end
47
+
data/script/console ADDED
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+ # File: script/console
3
+ irb = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb'
4
+
5
+ libs = " -r irb/completion"
6
+ # Perhaps use a console_lib to store any extra methods I may want available in the cosole
7
+ # libs << " -r #{File.dirname(__FILE__) + '/../lib/console_lib/console_logger.rb'}"
8
+ libs << " -r #{File.dirname(__FILE__) + '/../lib/re_expand.rb'}"
9
+ puts "Loading re_expand gem"
10
+ exec "#{irb} #{libs} --simple-prompt"
data/script/destroy ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
3
+
4
+ begin
5
+ require 'rubigen'
6
+ rescue LoadError
7
+ require 'rubygems'
8
+ require 'rubigen'
9
+ end
10
+ require 'rubigen/scripts/destroy'
11
+
12
+ ARGV.shift if ['--help', '-h'].include?(ARGV[0])
13
+ RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
14
+ RubiGen::Scripts::Destroy.new.run(ARGV)
data/script/generate ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
3
+
4
+ begin
5
+ require 'rubigen'
6
+ rescue LoadError
7
+ require 'rubygems'
8
+ require 'rubigen'
9
+ end
10
+ require 'rubigen/scripts/generate'
11
+
12
+ ARGV.shift if ['--help', '-h'].include?(ARGV[0])
13
+ RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
14
+ RubiGen::Scripts::Generate.new.run(ARGV)
@@ -0,0 +1,105 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ require 'Asearch'
4
+
5
+ class AsearchTest < Test::Unit::TestCase
6
+ def setup
7
+ end
8
+
9
+ def teardown
10
+ end
11
+
12
+ def test_init
13
+ a = Asearch.new('abc')
14
+ state = a.initstate
15
+ assert state[0] != 0
16
+ assert state[1] == 0
17
+ assert state[2] == 0
18
+ end
19
+
20
+ def test_match
21
+ #
22
+ # 状態を利用せず普通にマッチングを行なうメソッド
23
+ #
24
+ a = Asearch.new('abcde')
25
+ assert a.match('abcde')
26
+ assert a.match('abcde',1)
27
+ assert !a.match('abcd')
28
+ assert a.match('abcd',1)
29
+ end
30
+
31
+ def test_state
32
+ #
33
+ # "abcde"にマッチするかテスト
34
+ #
35
+ a = Asearch.new('abcde')
36
+ initstate = a.initstate
37
+ laststate = a.state(initstate,'abcde')
38
+ assert((laststate[0] & a.acceptpat) != 0)
39
+ laststate = a.state(initstate,'abcdf') # 1文字置換
40
+ assert((laststate[0] & a.acceptpat) == 0)
41
+ assert((laststate[1] & a.acceptpat) != 0)
42
+ assert((laststate[2] & a.acceptpat) != 0)
43
+ laststate = a.state(initstate,'abde') # 1文字欠損
44
+ assert((laststate[0] & a.acceptpat) == 0)
45
+ assert((laststate[1] & a.acceptpat) != 0)
46
+ assert((laststate[2] & a.acceptpat) != 0)
47
+ laststate = a.state(initstate,'abcfg') # 2文字置換
48
+ assert((laststate[0] & a.acceptpat) == 0)
49
+ assert((laststate[1] & a.acceptpat) == 0)
50
+ assert((laststate[2] & a.acceptpat) != 0)
51
+ laststate = a.state(initstate,'abe') # 2文字欠損
52
+ assert((laststate[0] & a.acceptpat) == 0)
53
+ assert((laststate[1] & a.acceptpat) == 0)
54
+ assert((laststate[2] & a.acceptpat) != 0)
55
+ laststate = a.state(initstate,'axbcde') # 1文字追加
56
+ assert((laststate[0] & a.acceptpat) == 0)
57
+ assert((laststate[1] & a.acceptpat) != 0)
58
+ assert((laststate[2] & a.acceptpat) != 0)
59
+ laststate = a.state(initstate,'axbcyde') # 2文字追加
60
+ assert((laststate[0] & a.acceptpat) == 0)
61
+ assert((laststate[1] & a.acceptpat) == 0)
62
+ assert((laststate[2] & a.acceptpat) != 0)
63
+ laststate = a.state(initstate,'ABCDF') # 大文字
64
+ assert((laststate[0] & a.acceptpat) == 0)
65
+ assert((laststate[1] & a.acceptpat) != 0)
66
+ assert((laststate[2] & a.acceptpat) != 0)
67
+
68
+ #
69
+ # ワイルドカード
70
+ #
71
+ a = Asearch.new(' abc def')
72
+ initstate = a.initstate
73
+ laststate = a.state(initstate,'abcdef')
74
+ assert((laststate[0] & a.acceptpat) != 0)
75
+ initstate = a.initstate
76
+ laststate = a.state(initstate,'abcXXXXdef')
77
+ assert((laststate[0] & a.acceptpat) != 0)
78
+ initstate = a.initstate
79
+ laststate = a.state(initstate,'abcXXXXYYY')
80
+ assert((laststate[0] & a.acceptpat) == 0)
81
+ initstate = a.initstate
82
+ laststate = a.state(initstate,'abcXXXXde')
83
+ assert((laststate[0] & a.acceptpat) == 0)
84
+ assert((laststate[1] & a.acceptpat) != 0)
85
+ assert((laststate[2] & a.acceptpat) != 0)
86
+ initstate = a.initstate
87
+ laststate = a.state(initstate,'ZZZZZabcdef')
88
+ assert((laststate[0] & a.acceptpat) != 0)
89
+
90
+ #
91
+ # 漢字
92
+ #
93
+ a = Asearch.new('漢字文字列')
94
+ initstate = a.initstate
95
+ laststate = a.state(initstate,'漢字文字列')
96
+ assert((laststate[0] & a.acceptpat) != 0)
97
+ laststate = a.state(initstate,'漢字文字')
98
+ assert((laststate[0] & a.acceptpat) == 0)
99
+ laststate = a.state(initstate,'漢字!文字列')
100
+ assert((laststate[0] & a.acceptpat) == 0)
101
+ assert((laststate[1] & a.acceptpat) != 0)
102
+ end
103
+
104
+ end
105
+
@@ -0,0 +1,36 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ require 'Generator'
4
+
5
+ class GeneratorTest < Test::Unit::TestCase
6
+ def setup
7
+ end
8
+
9
+ def teardown
10
+ end
11
+
12
+ def test_clock
13
+ g = Generator.new
14
+ g.add '(時計|時間|時刻)を(0|1|2|3|4|5|6|7|8|9|10|11|12)時に(セットする|設定する|あわせる)', 'set time #{$2}:00'
15
+ res = g.generate(' 10 ')
16
+ assert res[0].member?(['時刻を10時に設定する','set time 10:00'])
17
+ assert res[0].member?(['時計を10時にセットする','set time 10:00'])
18
+ assert !res[0].member?(['時計を8時にセットする','set time 8:00'])
19
+ end
20
+
21
+ def test_substring
22
+ g = Generator.new
23
+ g.add '(a)bcd(e(fg)h)i(jk)', '#{$1}/#{$2}/#{$3}/#{$4}'
24
+ res = g.generate(' b ')
25
+ assert res[0].member?(['abcdefghijk', 'a/efgh/fg/jk'])
26
+ assert !res[0].member?(['abcdefghijk', 'a/fgh/fg/jk'])
27
+ g.add '(ab|cd)efg(hij|klm)n', '#{$1}/#{$2}'
28
+ res = g.generate(' ef ')
29
+ assert res[0].member?(['abefghijn', 'ab/hij'])
30
+ assert res[0].member?(['cdefgklmn', 'cd/klm'])
31
+ end
32
+ end
33
+
34
+
35
+
36
+
@@ -0,0 +1,3 @@
1
+ require 'stringio'
2
+ require 'test/unit'
3
+ require File.dirname(__FILE__) + '/../lib/re_expand'
@@ -0,0 +1,11 @@
1
+ require File.dirname(__FILE__) + '/test_helper.rb'
2
+
3
+ class TestReExpand < Test::Unit::TestCase
4
+
5
+ def setup
6
+ end
7
+
8
+ def test_truth
9
+ assert true
10
+ end
11
+ end
@@ -0,0 +1,27 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ require 'Scanner'
4
+
5
+ class ScannerTest < Test::Unit::TestCase
6
+ def setup
7
+ end
8
+
9
+ def teardown
10
+ end
11
+
12
+ def test_1
13
+ s = Scanner.new('abc*def')
14
+ assert_equal s.gettoken, 'abc'
15
+ assert_equal s.gettoken, '*'
16
+ assert_equal s.gettoken, 'def'
17
+ end
18
+
19
+ def test_2
20
+ s = Scanner.new("(a\tb|c\td)")
21
+ assert_equal s.gettoken, "("
22
+ assert_equal s.gettoken, "a\tb"
23
+ assert_equal s.gettoken, '|'
24
+ assert_equal s.gettoken, "c\td"
25
+ assert_equal s.gettoken, ')'
26
+ end
27
+ end
metadata ADDED
@@ -0,0 +1,138 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: re_expand
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Toshiyuki Masui
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2012-04-30 00:00:00 Z
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: rdoc
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ~>
27
+ - !ruby/object:Gem::Version
28
+ hash: 19
29
+ segments:
30
+ - 3
31
+ - 10
32
+ version: "3.10"
33
+ type: :development
34
+ version_requirements: *id001
35
+ - !ruby/object:Gem::Dependency
36
+ name: newgem
37
+ prerelease: false
38
+ requirement: &id002 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ hash: 5
44
+ segments:
45
+ - 1
46
+ - 5
47
+ - 3
48
+ version: 1.5.3
49
+ type: :development
50
+ version_requirements: *id002
51
+ - !ruby/object:Gem::Dependency
52
+ name: hoe
53
+ prerelease: false
54
+ requirement: &id003 !ruby/object:Gem::Requirement
55
+ none: false
56
+ requirements:
57
+ - - ~>
58
+ - !ruby/object:Gem::Version
59
+ hash: 27
60
+ segments:
61
+ - 2
62
+ - 12
63
+ version: "2.12"
64
+ type: :development
65
+ version_requirements: *id003
66
+ description: |-
67
+ Generates all the text strings which match the given regexp.
68
+ If a filter pattern is given, the output is filtered by the pattern.
69
+ email:
70
+ - masui@pitecan.com
71
+ executables: []
72
+
73
+ extensions: []
74
+
75
+ extra_rdoc_files:
76
+ - History.txt
77
+ - Manifest.txt
78
+ - PostInstall.txt
79
+ files:
80
+ - History.txt
81
+ - Manifest.txt
82
+ - PostInstall.txt
83
+ - README.rdoc
84
+ - Rakefile
85
+ - lib/re_expand.rb
86
+ - lib/Generator.rb
87
+ - lib/Node.rb
88
+ - lib/Asearch.rb
89
+ - lib/Scanner.rb
90
+ - script/console
91
+ - script/destroy
92
+ - script/generate
93
+ - test/test_helper.rb
94
+ - test/test_re_expand.rb
95
+ - test/test_asearch.rb
96
+ - test/test_generator.rb
97
+ - test/test_scanner.rb
98
+ - .gemtest
99
+ homepage: http://github.com/masui/expand-ruby
100
+ licenses: []
101
+
102
+ post_install_message: PostInstall.txt
103
+ rdoc_options:
104
+ - --main
105
+ - README.rdoc
106
+ require_paths:
107
+ - lib
108
+ required_ruby_version: !ruby/object:Gem::Requirement
109
+ none: false
110
+ requirements:
111
+ - - ">="
112
+ - !ruby/object:Gem::Version
113
+ hash: 3
114
+ segments:
115
+ - 0
116
+ version: "0"
117
+ required_rubygems_version: !ruby/object:Gem::Requirement
118
+ none: false
119
+ requirements:
120
+ - - ">="
121
+ - !ruby/object:Gem::Version
122
+ hash: 3
123
+ segments:
124
+ - 0
125
+ version: "0"
126
+ requirements: []
127
+
128
+ rubyforge_project: re_expand
129
+ rubygems_version: 1.8.23
130
+ signing_key:
131
+ specification_version: 3
132
+ summary: Generates all the text strings which match the given regexp
133
+ test_files:
134
+ - test/test_asearch.rb
135
+ - test/test_generator.rb
136
+ - test/test_helper.rb
137
+ - test/test_re_expand.rb
138
+ - test/test_scanner.rb