<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 閱讀(1333) 評論(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 的代碼 有點難看
    主站蜘蛛池模板: 亚洲成_人网站图片| 亚洲另类图片另类电影| 未满十八私人高清免费影院| 免费视频淫片aa毛片| 亚洲国产无线乱码在线观看| 免费观看成人毛片a片2008| 亚洲高清一区二区三区| 成人毛片免费在线观看| 亚洲视频在线观看2018| 成人免费一区二区三区在线观看| 亚洲综合av一区二区三区不卡 | 国产免费爽爽视频免费可以看| 激情五月亚洲色图| 免费无码成人AV片在线在线播放| 亚洲精品色播一区二区| 亚洲国产电影av在线网址| 中文字幕久无码免费久久| 亚洲人成电影福利在线播放| 最近免费中文字幕高清大全| 亚洲人成人网毛片在线播放| 免费无码又爽又刺激毛片| 男女作爱免费网站| 国产亚洲色婷婷久久99精品| 精品熟女少妇av免费久久| 亚洲kkk4444在线观看| 免费va人成视频网站全| a级毛片在线视频免费观看| 亚洲免费观看在线视频| 免费一级毛片在线播放不收费| 国产自国产自愉自愉免费24区| 亚洲精品成人图区| 国产极品粉嫩泬免费观看| 免费无码H肉动漫在线观看麻豆| 亚洲国产精品成人精品软件 | 亚洲一区二区三区自拍公司| 99在线观看视频免费| 色偷偷噜噜噜亚洲男人| 亚洲va久久久噜噜噜久久男同| 国产1024精品视频专区免费| xxxxxx日本处大片免费看| 亚洲日本国产精华液|