我在json中有很多课程,每门课程都有一个先决条件字段,其中包含该特定课程的先决条件列表,如下所示:
(为简单起见,我们只遵循AAAA111格式)
AAAA111, BBB111, CCC101, DDD104
每个课程都遵循格式\w{3,4}\d{3}
,因此在python中使用正则表达式获取每个课程并不太困难。
问题:
我不知道天才是谁认为这是一个很好的方式,但是没有一致的格式如何列出先决条件列表。以下是我发现的一些列表示例格式:
AAAA111, BBB111, CCC101, and DDD104
AAAA111, BBB111, CCC101 or DDD104
AAAA111, AAAA112 or AAAA113, BBB333
AAA111 or BBB111, AND CCC111
AAA111 or BBB111 or CCC111 or DDD111
AAA111 or 112 or 222 or 333
AAA111 or instructor permission
AAA111/221
and so on... :(
有成千上万的课程,我发现这么多不同的格式,有时候我想知道如果怪物存在的话,手工完成所有内容会更好。
因此,提取使用正则表达式提及的特定课程来解析匹配\w{3,4}\d{3}
并不难。使用正则表达式来匹配or
,and
或instructor permission
等关键字的存在也不难。
我被困住的地方是保留上下文。
在上面的例子中:
AAAA111, BBB111, CCC101, and DDD104
这样的先决条件清单意味着这门课程需要全部4个。
AAAA111, BBB111, CCC101 or DDD104
AAA111 or 112 or 222 or 333
此类先决条件清单表示此课程仅需要4个中的一个或多个。
AAAA111, AAAA112 or AAAA113, BBB333
但对于像这样的怪人......
我该怎么办?显然,只有在or
或and
或其他此类关键字出现时激活的标记才能生效。我坚持如何在保持上下文的同时最好地解析它。人类阅读这可以很容易地弄清楚背景是什么,但是......
答案 0 :(得分:1)
您可以尝试使用pyparsing
这是一个很棒的库来处理语法。
如果条目具有一致(布尔)逻辑,并且您知道如何解释and
和or
之间的逗号,那么您可以尝试使用基于{的脚本解析条目{3}}来自pyparsing的例子:
import pprint
import string
from pyparsing import Word, nums, Literal, opAssoc, operatorPrecedence
course_name = Word(string.ascii_uppercase + nums + "/") | Literal("instructor permission")
comma_separator = Literal(',')
comma_separator.setParseAction(lambda t:"&&")
and_separator = Literal(', and') | Literal(', AND') | Literal('and') | Literal('AND')
and_separator.setParseAction(lambda t:"&&")
or_separator = Literal('or') | Literal("OR")
or_separator.setParseAction(lambda t:"||")
course_line = operatorPrecedence(course_name,
[
(and_separator, 2, opAssoc.LEFT,),
(or_separator, 2, opAssoc.LEFT),
(comma_separator, 2, opAssoc.LEFT,),
])
data = """AAAA111, BBB111, CCC101, and DDD104
AAAA111, BBB111, CCC101 or DDD104
AAAA111, AAAA112 or AAAA113, BBB333
AAA111 or BBB111, AND CCC111
AAA111 or BBB111 or CCC111 or DDD111
AAA111 or 112 or 222 or 333
AAA111 or instructor permission
AAA111/221
"""
for line in data.splitlines():
results = course_line.parseString(line)
print(line)
pprint.pprint(results.asList()[0])
print()
打印:
AAAA111, BBB111, CCC101, and DDD104
['AAAA111', '&&', 'BBB111', '&&', ['CCC101', '&&', 'DDD104']]
AAAA111, BBB111, CCC101 or DDD104
['AAAA111', '&&', 'BBB111', '&&', ['CCC101', '||', 'DDD104']]
AAAA111, AAAA112 or AAAA113, BBB333
['AAAA111', '&&', ['AAAA112', '||', 'AAAA113'], '&&', 'BBB333']
AAA111 or BBB111, AND CCC111
['AAA111', '||', ['BBB111', '&&', 'CCC111']]
AAA111 or BBB111 or CCC111 or DDD111
['AAA111', '||', 'BBB111', '||', 'CCC111', '||', 'DDD111']
AAA111 or 112 or 222 or 333
['AAA111', '||', '112', '||', '222', '||', '333']
AAA111 or instructor permission
['AAA111', '||', 'instructor permission']
AAA111/221
'AAA111/221'