Ok, entonces hice un montón de preguntas más pequeñas sobre este proyecto, pero todavía no tengo mucha confianza en los diseños que voy a desarrollar, por lo que voy a hacer una pregunta en una escala más amplia .¿Cuál es la mejor manera de analizar una gramática simple?
Estoy analizando descripciones de requisitos previos para un catálogo de cursos. Las descripciones casi siempre siguen una cierta forma, lo que me hace pensar que puedo analizar la mayoría de ellas.
Desde el texto, me gustaría generar un gráfico de las relaciones de los requisitos previos del curso. (Esa parte será fácil, después de haber analizado los datos.)
Algunas entradas y salidas de la muestra:
"CS 2110" => ("CS", 2110) # 0
"CS 2110 and INFO 3300" => [("CS", 2110), ("INFO", 3300)] # 1
"CS 2110, INFO 3300" => [("CS", 2110), ("INFO", 3300)] # 1
"CS 2110, 3300, 3140" => [("CS", 2110), ("CS", 3300), ("CS", 3140)] # 1
"CS 2110 or INFO 3300" => [[("CS", 2110)], [("INFO", 3300)]] # 2
"MATH 2210, 2230, 2310, or 2940" => [[("MATH", 2210), ("MATH", 2230), ("MATH", 2310)], [("MATH", 2940)]] # 3
Si toda la descripción es sólo un curso, que se emite directamente.
Si los cursos son unidos ("y"), que son todos de salida en la misma lista
Si el curso se disocian ("o"), que están en listas separadas
Aquí, tenemos tanto "y" y "o".
Una advertencia que hace que sea más fácil: parece que la anidación de las frases "y"/"o" nunca es mayor que el del ejemplo 3.
¿Cuál es la mejor manera de hacer esto ? Empecé con PLY, pero no pude resolver cómo resolver los conflictos de reducción/reducción. La ventaja de PLY es que es fácil de manipular lo que genera cada regla de análisis:
def p_course(p):
'course : DEPT_CODE COURSE_NUMBER'
p[0] = (p[1], int(p[2]))
Con PyParse, es menos claro cómo modificar la salida de parseString()
. Estaba pensando en la idea de @Alex Martelli de mantener el estado en un objeto y aumentar el rendimiento de eso, pero no estoy seguro de cómo hacerlo mejor.
def addCourse(self, str, location, tokens):
self.result.append((tokens[0][0], tokens[0][1]))
def makeCourseList(self, str, location, tokens):
dept = tokens[0][0]
new_tokens = [(dept, tokens[0][1])]
new_tokens.extend((dept, tok) for tok in tokens[1:])
self.result.append(new_tokens)
Por ejemplo, para manejar "o" casos:
def __init__(self):
self.result = []
# ...
self.statement = (course_data + Optional(OR_CONJ + course_data)).setParseAction(self.disjunctionCourses)
def disjunctionCourses(self, str, location, tokens):
if len(tokens) == 1:
return tokens
print "disjunction tokens: %s" % tokens
¿Cómo disjunctionCourses()
saben qué frases más pequeño para disjoin? Todo lo que obtiene son tokens, pero lo que se ha analizado hasta ahora se almacena en result
, entonces, ¿cómo puede la función indicar qué datos en result
corresponden a qué elementos de token
? Creo que podría buscar a través de las fichas, y luego encontrar un elemento de result
con los mismos datos, pero que se sienten enrevesado ...
Además, hay muchas descripciones que incluyen texto misceláneos, como:
"CS 2110 or permission of instructor"
"INFO 3140 or equivalent experience"
"PYSCH 2210 and sophomore standing"
Pero no es crítico que analice ese texto.
¿Cuál es una mejor manera de abordar este problema?
La numeración en las entradas y salidas de muestra no coincide con la numeración en su discusión de ellas. –