好的,所以我之前问了很多关于这个项目的小问题,但我对我设计的内容并没有太多信心,所以我要在更广泛的范围内提出一个问题。
我正在解析课程目录的先决条件描述。这些描述几乎总是遵循一定的形式,这让我觉得我可以解析它们中的大部分。
从文本中,我想生成一张课程先决条件关系图。(在我解析数据后,这部分将很容易。)
以下是一些示例输入和输出:
"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
如果整个描述只是一个课程,则直接输出。
如果课程被连接(“和”),则它们都在同一个列表中输出。
如果课程是分离的(“或”),则它们在不同的列表中。
这里有“和”和“或”两种情况。
值得注意的是,它似乎永远不会出现比示例3中展示的更大的嵌套“and”/“or”短语。
最佳方法是什么?我先尝试了 PLY,但是我没法解决 reduce/reduce 冲突。PLY 的优点是可以轻松操作每个解析规则生成的内容:
def p_course(p):
'course : DEPT_CODE COURSE_NUMBER'
p[0] = (p[1], int(p[2]))
使用 PyParse,不太清楚如何修改 parseString()
的输出。我考虑借鉴 @Alex Martelli 的想法,将状态保存在对象中并从该对象构建输出,但我不确定最佳实践是什么。
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)
例如,处理“or”情况的方法是: 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
disjunctionCourses()
函数如何知道要分离哪些较小的短语?它只得到了令牌,但已解析的内容存储在result
中,那么该函数如何确定result
中的哪个数据对应于token
的哪些元素呢?我想我可以搜索令牌,然后找到与相同数据匹配的result
元素,但这看起来有些复杂...此外,还有许多包含杂项文本的描述,例如:"CS 2110 or permission of instructor"
"INFO 3140 or equivalent experience"
"PYSCH 2210 and sophomore standing"
但是解析那段文本并不是至关重要的。
有一个更好的方法来解决这个问题吗?