正規表現からその正規表現にマッチするような例を生成する
本当にやりたいことは、
型から、その型を持つようなRubyプログラムを生成する
なんだけど(というかこれはHaskell界隈の人が喜んでやってるやつだよな、つまんね)、とりあえず正規表現で考えてみてた。
正規表現は有限状態オートマトンになるわけで、ループがあるとやだなぁ、とか考えてたんだけど、研究室の後輩(オートマトン屋さん)に相談してみたら、少なくとも正規表現に限定してしまえば簡単になると言われた。確かに、よく考えてみれば、ループがある場合は*とかで明示されてる。そういうわけで30分くらいで作ったプログラム。
実行例:
$ ruby regen.rb /red|blue|green|(#[01234567890ABCDEF][01234567890ABCDEF][01234567890ABCDEF][01234567890ABCDEF][01234567890ABCDEF][01234567890ABCDEF]?)/ OK : #9405D9 OK : #5D06FC OK : red OK : #298 OK : #D0347B OK : blue OK : red OK : green OK : blue OK : blue
JavaScriptで書いておいて、簡単なパーサも書けば、Webで試してもらえて楽しいと思う。気が向いたらやるかも。
module RE class Literal def initialize(c) @char = c end def example() @char end def to_re() @char end end class Group def initialize(res) @res = res end def example() @res.collect {|re| re.example() }.join('') end def to_re() "(" + @res.collect{|re| re.to_re}.join('') + ")" end end class Alter def initialize(res) @res = res end def example() @res[rand(@res.length)].example() end def to_re() @res.collect {|re| re.to_re}.join('|') end end class Star def initialize(re) @re = re end def example() acc = "" rand(10).times { acc += @re.example() } acc end def to_re() @re.to_re + "*" end end class Set def initialize(set) @set = set end def example() @set[rand(@set.length)] end def to_re() "[#{@set.join('')}]" end end class Sequence def initialize(seq) @seq = seq end def example() @seq.collect{|re| re.example }.join('') end def to_re() @seq.collect{|re| re.to_re}.join('') end end class Question def initialize(re) @re = re end def example() rand(2) == 0 ? @re.example : "" end def to_re() @re.to_re+"?" end end end include RE a = /#[0123456789ABCDEF][0123456789ABCDEF][0123456789ABCDEF]([0123456789ABCDEF][0123456789ABCDEF][0123456789ABCDEF])?|red|blue|green/ b = %w(0 1 2 3 4 5 6 7 8 9 0 A B C D E F) d = Set.new(b) fff = Group.new([Literal.new("#"), d, d, d, Question.new(Sequence.new([d, d, d]))]) lit = %w(red blue green).collect{|l| Literal.new(l) } lit << fff re = Alter.new(lit) puts "/#{re.to_re}/" 10.times { s = re.example puts("#{a=~s ? 'OK':'NG'} : #{s}") }