使用正则表达式在Python中保留上下文时解析句子的一部分

时间:2014-12-29 21:06:47

标签: python regex parsing

我在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}并不难。使用正则表达式来匹配orandinstructor 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

但对于像这样的怪人......

我该怎么办?显然,只有在orand或其他此类关键字出现时激活的标记才能生效。我坚持如何在保持上下文的同时最好地解析它。人类阅读这可以很容易地弄清楚背景是什么,但是......

编辑:由于清晰度似乎是一个问题,我会在这里尝试更清楚。 我想要做的是为所有课程更改每个课程的每个必修课程列表,以便它们都具有一致的,编程可读的格式。

1 个答案:

答案 0 :(得分:1)

您可以尝试使用pyparsing这是一个很棒的库来处理语法。

如果条目具有一致(布尔)逻辑,并且您知道如何解释andor之间的逗号,那么您可以尝试使用基于{的脚本解析条目{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'