2010-03-04 4 views
5

Ben bir dize Ruby en iyi yöntem bu dizeyi ayrıştırmak için nasılYakut ayrıştırma dize

input = "maybe (this is | that was) some ((nice | ugly) (day |night) | (strange (weather | time)))" 

var? belki bu belki bu bazı garip zaman

oldu

bazı güzel geceydi bazı çirkin gece belki

olduğunu

:

Senaryonun böyle sententes inşa etmek mümkün olmalıdır demek

Ve böyle devam ediyor, noktayı aldınız ...

char karakterini char ile okuyayım ve daha sonra hesaplama için parantez değerlerini depolamak için yığın içeren bir durum makinesi mi yoksa daha iyi bir yaklaşım mı var?

Belki de böyle bir amaç için kutu kitaplığı dışında hazır mısınız?

cevap

8

Treetop. Dilbilgisini tanımlamak için Ruby benzeri bir DSL. Verdiğiniz dizeyi ayrıştırma oldukça kolay olmalı ve gerçek bir ayrıştırıcı kullanarak dilbilginizi daha sonra kolayca genişletebileceksiniz.

Eğer ayrıştırmak istediğiniz dize türü için bir örnek dilbilgisi (sentences.treetop olarak kaydetmek):

grammar Sentences 
    rule sentence 
    # A sentence is a combination of one or more expressions. 
    expression* <Sentence> 
    end 

    rule expression 
    # An expression is either a literal or a parenthesised expression. 
    parenthesised/literal 
    end 

    rule parenthesised 
    # A parenthesised expression contains one or more sentences. 
    "(" (multiple/sentence) ")" <Parenthesised> 
    end 

    rule multiple 
    # Multiple sentences are delimited by a pipe. 
    sentence "|" (multiple/sentence) <Multiple> 
    end 

    rule literal 
    # A literal string contains of word characters (a-z) and/or spaces. 
    # Expand the character class to allow other characters too. 
    [a-zA-Z ]+ <Literal> 
    end 
end 

gramer yukarıda bize düğüm değerlerini erişmesine izin sınıfları tanımlayan bir beraberindeki dosyaya ihtiyacı (sentence_nodes.rb olarak kaydedin).

class Sentence < Treetop::Runtime::SyntaxNode 
    def combine(a, b) 
    return b if a.empty? 
    a.inject([]) do |values, val_a| 
     values + b.collect { |val_b| val_a + val_b } 
    end 
    end 

    def values 
    elements.inject([]) do |values, element| 
     combine(values, element.values) 
    end 
    end 
end 

class Parenthesised < Treetop::Runtime::SyntaxNode 
    def values 
    elements[1].values 
    end 
end 

class Multiple < Treetop::Runtime::SyntaxNode 
    def values 
    elements[0].values + elements[2].values 
    end 
end 

class Literal < Treetop::Runtime::SyntaxNode 
    def values 
    [text_value] 
    end 
end 

Aşağıdaki örnek programı

size verdik örnek bir cümle ayrıştırmak için oldukça basit olduğunu göstermektedir.

require "rubygems" 
require "treetop" 
require "sentence_nodes" 

str = 'maybe (this is|that was) some' + 
    ' ((nice|ugly) (day|night)|(strange (weather|time)))' 

Treetop.load "sentences" 
if sentence = SentencesParser.new.parse(str) 
    puts sentence.values 
else 
    puts "Parse error" 
end 

Bu programın çıktısı:

maybe this is some nice day 
maybe this is some nice night 
maybe this is some ugly day 
maybe this is some ugly night 
maybe this is some strange weather 
maybe this is some strange time 
maybe that was some nice day 
maybe that was some nice night 
maybe that was some ugly day 
maybe that was some ugly night 
maybe that was some strange weather 
maybe that was some strange time 

Ayrıca sözdizimi ağacı erişebilirsiniz:

p sentence 

The output is here.

Elinizde: 50 satırlık kodda yapmak istediğiniz şeye oldukça yakın gelmesi gereken ölçeklenebilir bir çözümleme çözümü. Bu yardımcı olur mu?

+0

Teşekkürler, net üzerindeki örnekleri okudum, ancak yuvalanmış parantezleri nasıl okuyabildiğimi anlamıyorum ... – astropanic

+0

Teşekkürler! Sen benim kahramanımsın :) – astropanic

+0

http://www.bestechvideos.com/2008/07/18/rubyconf-2007-treetop-syntactic-analysis-with-ruby, güzel video – astropanic