<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    莊周夢蝶

    生活、程序、未來
       :: 首頁 ::  ::  :: 聚合  :: 管理

    用Ruby寫了個NFA

    Posted on 2008-02-25 17:46 dennis 閱讀(1335) 評論(1)  編輯  收藏 所屬分類: 動態語言計算機科學與基礎
        今天有點空閑,想想用Ruby寫個NFA試試。從正則表達式構造NFA采用經典的Thompson算法:正則表達式 -> 后綴表達式 -> 構造NFA。構造了NFA后,用之匹配字符串。一句話,寫了個玩具的正則表達式引擎,支持concatenation、alternation以及*、?、+量詞,不支持反向引用和轉義符。測試了下與Ruby自帶的正則表達式引擎的性能對比,慢了3倍。構造NFA沒什么問題,主要是匹配運行寫的爛,有空再改改。

    nfa.rb

    module NFA
      
    class NFA
        
    def initialize(state)
          @state
    =state
        end
        
    def step(clist,c)
          
    return clist if clist.size==0;
          nlist
    =[] 
          allNull 
    = true
          matched 
    = false
          clist.each do 
    |t|
            
    if !t.nil?
              allNull 
    = false if t.c!=-1
              
    if t.c == c && t.end.type ==1 then
                matched 
    = true
                nlist.push(t.end.out1) 
    if !t.end.out1.end.nil? 
                nlist.push(t.end.out2) 
    if !t.end.out2.end.nil?
              elsif (t.c 
    == c && t.end.type == 0) then
                matched 
    = true;
                
    return ListUitls.new_list(t);
              elsif (t.c 
    == -1 && !t.end.nil?) then
                nlist.push(t.end.out1);
                nlist.push(t.end.out2);
              end
            end
          end        
          
    return step(nlist, c) if (allNull)
          
    return step(nlist, c) if (!matched)
          nlist
        end
        
    def test?(s)
          match(@state,s)
        end
        
    def match(state,s)
          clist 
    =[]
          clist.push(state.out1);
          clist.push(state.out2);
          s.each_byte do 
    |c|
            c 
    =c&0xFF;
            clist 
    = step(clist, c);
            
    return false if clist.size==0
          end
          
    return is_match?(clist)
        end
        
    def is_match?(clist)
          clist.each  do 
    |t|
            
    return true if !t.nil? and t.c==-1 and t.end and t.end.is_matched? 
          end
          false
        end
      end
      
    class Paren
        attr_accessor:n_alt,:n_atom
      end
      
    class State
        attr_accessor :out1,:out2,:type
        
    def initialize(out1,out2)
          @out1
    =out1
          @out2
    =out2
          @type
    =1
        end
        
    def is_matched?
          
    return @type==0
        end
      end
      
    class Transition
        attr_accessor :c,:end
        
    def initialize(c)
          @c
    =c
        end   
      end
      
    class Frame
        attr_accessor :start,:outs
        
    def initialize(start,outs)
          @start
    =start
          @outs
    =outs
        end
      end
      
    class ListUitls
        
    def self.link(list,state)
          list.each{
    |t| t.end=state}
        end
        
    def self.append(list1,list2)
          list1
    +list2
        end
        
    def self.new_list(out)
          result
    =[]
          result.push(out)
          result      
        end
      end
      
    def self.compile(re)
        post 
    = re2post(re)
        
    raise ArgumentError.new,"bad regexp!" if post.nil?
        state 
    = post2nfa(post);
        
    raise RuntimeError.new,"construct nfa from postfix fail!" if state.nil?        
        
    return NFA.new(state);
      end
      
    def self.post2nfa(postfix)
        stack
    =[]
        s
    =nil
        t
    =t1=t2=nil 
        e1
    =e2=e=nil 
        
    return nil if postfix.nil?
        postfix.each_byte do 
    |p|
          case p.chr
          when 
    '.':
            e2 
    = stack.pop() 
            e1 
    = stack.pop() 
            ListUitls.link(e1.outs, e2.start) 
            stack.push(Frame.new(e1.start, e2.outs)) 
          when 
    '|':
            e2 
    = stack.pop() 
            e1 
    = stack.pop() 
            t1 
    = Transition.new(-1)
            t2 
    = Transition.new(-1
            t1.end 
    = e1.start 
            t2.end 
    = e2.start 
            s 
    = State.new(t1, t2) 
            stack.push(Frame.new(s, ListUitls.append(e1.outs, e2.outs))) 
          when 
    '?':
            e 
    = stack.pop() 
            t1 
    = Transition.new(-1)
            t2 
    = Transition.new(-1
            t1.end 
    = e.start 
            s 
    = State.new(t1, t2) 
            stack.push(Frame.new(s, ListUitls.append(e.outs, ListUitls.new_list(t2)))) 
          when 
    '*':
            e 
    = stack.pop() 
            t1 
    = Transition.new(-1)
            t2 
    = Transition.new(-1)
            t1.end 
    = e.start 
            s 
    = State.new(t1, t2) 
            ListUitls.link(e.outs, s) 
            stack.push(Frame.new(s, ListUitls.new_list(s.out2))) 
          when 
    '+':
            e 
    = stack.pop() 
            t1 
    = Transition.new(-1
            t2 
    = Transition.new(-1)
            t1.end 
    = e.start 
            s 
    = State.new(t1, t2) 
            ListUitls.link(e.outs, s) 
            stack.push(Frame.new(e.start, ListUitls.new_list(t2))) 
          
    else
            t 
    = Transition.new(p) 
            s 
    = State.new(t, Transition.new(-1)) 
            stack.push(Frame.new(s, ListUitls.new_list(s.out1))) 
          end
        end
        e 
    = stack.pop() 
        
    return nil if stack.size()>0
        end_state 
    = State.new(nil, nil) 
        end_state.type
    =0
        e.outs.each do 
    |tran|
          
    if tran.c!=-1
            t1 
    = Transition.new(-1)
            t2 
    = Transition.new(-1
            s
    =State.new(t1,t2)
            tran.end
    =s
            s.out1.end
    =end_state
            s.out2.end
    =end_state
          
    else
            tran.end
    =end_state         
          end
        end
        start 
    = e.start 
        
    return start 
      end
      
    def self.re2post(re)
        n_alt 
    = n_atom = 0 
        result
    =""
        paren
    =[]
        re.each_byte do 
    |c|
          case c.chr  
          when 
    '(' then
            
    if (n_atom > 1) then
              n_atom
    -=1 
              result
    <<"."
            end
            p 
    =Paren.new 
            p.n_alt 
    = n_alt 
            p.n_atom 
    = n_atom 
            paren.push(p) 
            n_alt 
    = n_atom = 0
          when 
    '|' then
            
    if (n_atom == 0)
              
    return nil
            end
            
    while (n_atom-=1> 0 
              result
    <<"."
            end
            n_alt
    +=1
          when 
    ')' then
            
    if (paren.size() == 0)
              
    return nil
            end                
            
    if (n_atom == 0)
              
    return nil 
            end
            
    while (n_atom-=1)>
              result
    <<"." 
            end
            
    while(n_alt>0)  
              result
    <<"|" 
              n_alt
    -=1
            end
            p 
    = paren.pop()
            n_alt 
    = p.n_alt 
            n_atom 
    = p.n_atom 
            n_atom
    +=1
          when 
    '*','+','?':
            
    if (n_atom == 0)
              
    return nil 
            end
            result
    <<
          
    else 
            
    if (n_atom > 1
              n_atom
    -=1 
              result
    <<"."
            end
            result
    <<
            n_atom
    +=1
          end
        end
        
    return nil if paren.size()>0
        
    while ( (n_atom-=1)> 0)
          result
    <<"." 
        end
        
    while(n_alt>0)
          n_alt
    -=1
          result
    <<"|" 
        end
        result
      end
    end

    使用:
     nfa = NFA::compile("a(bb)+a(cdf)*")
     
    assert nfa.test?("abba")
     
    assert nfa.test?("abbbba")
     
    assert !nfa.test?("a"
     
    assert !nfa.test?("aa"
     
    assert nfa.test?("abbacdf")
     
    assert nfa.test?("abbbbacdfcdf")
     
    assert !nfa.test?("bbbbacdfcdf")
     
    assert !nfa.test?("abbbacdfcdf")
     
    assert !nfa.test?("abbbbacdfdf")
     
    assert !nfa.test?("abbbbacdfdfg")



    評論

    # re: 用Ruby寫了個NFA  回復  更多評論   

    2008-02-26 08:57 by left
    好像ruby 的代碼 有點難看
    主站蜘蛛池模板: 狼群影院在线观看免费观看直播| a级毛片黄免费a级毛片| 免费高清在线影片一区| 亚洲欧洲日韩极速播放| 毛片免费视频播放| 亚洲人成电影在线观看网| 特级做A爰片毛片免费69 | 大地资源免费更新在线播放| 亚洲最大中文字幕| 日本亚洲免费无线码| 亚洲中文字幕AV每天更新| 大学生美女毛片免费视频| 国产亚洲精品美女久久久久 | 亚洲字幕在线观看| 99re热免费精品视频观看| 亚洲人成人无码.www石榴| 国产成人免费一区二区三区| 黄色免费在线观看网址| 亚洲宅男天堂在线观看无病毒| 国产亚洲免费的视频看| 亚洲导航深夜福利| 免费一级一片一毛片| 免费欧洲美女牲交视频| 国产亚洲综合一区二区三区| 午夜无码A级毛片免费视频 | 国产成人精品亚洲2020| 全免费一级午夜毛片| 日本中文字幕免费看| 亚洲狠狠婷婷综合久久久久| 曰批视频免费40分钟试看天天| 日韩精品免费电影| 亚洲乱码日产一区三区| 美女在线视频观看影院免费天天看| 久久亚洲精精品中文字幕| 丁香花免费高清视频完整版 | 在线视频亚洲一区| 国产亚洲精品影视在线产品 | 久久久久久AV无码免费网站| 亚洲另类图片另类电影| 亚洲熟妇少妇任你躁在线观看无码| 亚欧免费一级毛片|