2010-03-04 27 views
5

que tiene una cadenaRubí cadena de análisis

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

¿Cómo es el mejor método en Ruby para analizar esta cadena?

me refiero a la secuencia de comandos debe ser capaz de construir sententes así:

tal vez esta es una noche fea

tal vez era un poco agradable noche

quizás esto era un tiempo extraño

Y así sucesivamente, usted consiguió el punto ...

¿Debo leer la cadena char by char y bulid una máquina de estado con una pila para almacenar los valores de paréntesis para el cálculo posterior, o hay un mejor enfoque?

¿Quizás una biblioteca preparada y lista para tal fin?

Respuesta

8

Probar Treetop. Es un DSL similar a Ruby para describir gramáticas. Analizar el hilo que has dado debería ser bastante fácil, y al usar un analizador real podrás extender tu gramática más tarde.

una gramática ejemplo para el tipo de cadena que se desea analizar (guardar como 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 

La gramática anterior necesita un archivo adjunto que define las clases que nos permiten acceder a los valores de los nodos (guardar como 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 

El siguiente programa de ejemplo muestra que es bastante simple analizar la oración de ejemplo que ha dado.

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 

La salida de este programa es:

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 

También puede acceder al árbol de sintaxis:

p sentence 

The output is here.

Ahí lo tienes: una solución de análisis escalable que debería acercarse bastante a lo que quieres hacer en aproximadamente 50 líneas de código. ¿Eso ayuda?

+0

Gracias, he leído los ejemplos en la red, pero no entiendo cómo puedo leer paréntesis anidados ... – astropanic

+0

¡Gracias, amigo! Eres mi héroe :) – astropanic

+0

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