2010-03-04 8 views
5

Ich habe eine ZeichenfolgeRuby-Parse String

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

Wie ist die beste Methode in Ruby diese Zeichenfolge zu analysieren?

Ich meine das Skript der Lage sein sollte sententes so bauen:

vielleicht dies einige hässliche Nacht ist

vielleicht, dass einige schöne Nacht war

vielleicht dieses eine seltsame Zeit war

Und so weiter, Sie haben den Punkt ...

Soll ich die Zeichenfolge char von char lesen und eine Zustandsmaschine mit einem Stapel bulid die Klammer Wert für die spätere Berechnung zu speichern, oder gibt es eine bessere Lösung?

Vielleicht eine fertige, aus der Box-Bibliothek für diesen Zweck?

Antwort

8

Versuchen Sie Treetop. Es ist ein Ruby-ähnliches DSL, um Grammatiken zu beschreiben. Das Analysieren der Zeichenfolge, die Sie angegeben haben, sollte ziemlich einfach sein, und mit einem echten Parser können Sie Ihre Grammatik später leicht erweitern.

Ein Beispiel Grammatik für die Art der Zeichenfolge, die Sie analysieren wollen (speichern als sentences.treetop):

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 

Die Grammatik eine begleitende Datei oben benötigt, die die Klassen definiert, die uns die Knotenwerte erlauben den Zugriff auf (speichern unter sentence_nodes.rb).

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 

Das folgende Beispielprogramm zeigt, dass es sehr einfach ist, den von Ihnen angegebenen Beispielsatz zu analysieren.

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 

Die Ausgabe dieses Programms ist:

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 

Sie können auch den Syntaxbaum zugreifen:

p sentence 

The output is here.

Da haben Sie es: eine skalierbare Parsing-Lösung, die in etwa 50 Zeilen Code ziemlich nahe an das kommen soll, was Sie tun möchten. Hilft das?

+0

Danke, ich habe die Beispiele im Netz gelesen, aber ich verstehe nicht, wie ich verschachtelte Klammern lesen kann ... – astropanic

+0

Danke Man! Du bist mein Held :) – astropanic

+0

http://www.bestechvideos.com/2008/07/18/rubyconf-2007-treetop-syntactic-analysis-with-ruby, schönes Video – astropanic