首页 > 解决方案 > 使用正则表达式作为课程目录的 Python 解析器

问题描述

我一直在尝试为旧课程目录开发一种解析器,并且知道我想做什么但无法弄清楚。基本上,前提是我要解析并找到课程缩写,所以Computer Science会缩写为“(CSC)”。接下来,我需要找到课程编号、课程名称和课程单元。我的正则表达式模式很简单:

course_abbrev = re.compile('\([A-Z]{3}\)')
course_num = re.compile('[0-9]{3},?')
course_title = re.compile('.+?(?=I )')
course_units = re.compile('\d')

目录的格式都略有不同,但相对如下:

"""
Computer Science (CSC)  
Chairman: ...
201 Introduction to Computing I, 3
(Information of the course)...

220 Another Comp Class I, 3
(Information)... 
...  
...
...

Dental Hygiene (DHY)
Chairman: ...
101...
"""

目录的文本有些混乱,因为它是通过 PyPDF2 读取的,因为目录是 PDF 格式,但因此我是在阅读信息时读取一页。一种有效的方法是查找缩写,查找该缩写后面的数字,然后找到该数字后面的标题,然后是课程单元。re 模块有办法列出所有这些模式 (re.findall()) 或搜索其中一个 (re.search()) 但我不确定如何找到一个、存储它,然后找到不同的来自那里的正则表达式模式,存储它等等。
编辑:由于PyPDF2,输入看起来像这样,页面被分解并分离信息块:

COMPUTER SCIENCE (CSC) 
CHAIRMAN: Professor Name (Computer Science 
and Experimental Statistics) 
201 Introduction 
to Computing I and II, 3 
Algorithms, programs, and computers. Basic 
ming and program structure, data representation, 
zation and characteristics of computers. Computer 
tion of other stuff... 
(Lee. 3). Staff 220 Computers in Society 
II, 3 History, operation, application, and 
social significance of 
computers. Emphasis on the role of the computer in 
ciety with respect to more information and dan
gers. (Lee. 3) Carrano

标签: pythonregexparsingre

解决方案


一种选择是利用锚点通过PyPi 正则表达式模块\G获得迭代匹配。

在循环匹配时,您可以创建一个临时列表,仅当它不是 None 时才添加第一个组

然后将所有其他后续组添加到其中,最后将临时列表添加到结果列表中。

(?:^.* \(([A-Z]{3})\).*|\G(?!^))(?:\r?\n(?!\d{3} |.* \([A-Z]{3}\)[^\S\r\n]*$).*)*\r?\n(\d{3}) (.*?) I, (\d+)

解释

  • (?:非捕获组
    • ^.* \(([A-Z]{3})\).*字符串开头并在第 1 组中捕获三倍大写字符 AZ
    • |或者
    • \G(?!^)在上一场比赛结束时断言肯定,而不是在开始时
  • )关闭组
  • (?:非捕获组
    • \r?\n(?!匹配换行符并断言字符串不包含
    • \d{3} 匹配 3 位数字和空格
    • |或者
    • .* \([A-Z]{3}\)[^\S\r\n]*$).*匹配字符串末尾的 3 个大写字符 AZ
  • )*关闭组并重复 0 次或更多次
  • \r?\n匹配换行符
  • (\d{3}) (.*?) I, (\d+)匹配 3 组:大写前 3 个数字,theI后 1+ 个数字,I逗号和空格

正则表达式演示Python 演示

示例代码

import regex

pattern = r"(?:^.* \(([A-Z]{3})\).*|\G(?!^))(?:\r?\n(?!\d{3} |.* \([A-Z]{3}\)[^\S\r\n]*$).*)*\r?\n(\d{3}) (.*?) I, (\d+)"

test_str = ("Computer Science (CSC)\n"
            "Chairman: ...\n"
            "201 Introduction to Computing I, 3\n"
            "(Information of the course)...\n\n"
            "220 Another Comp Class I, 3\n"
            "(Information)... \n"
            "...  \n"
            "...\n"
            "...\n\n"
            "Dental Hygiene (DHY)  \n"
            "Chairman: ...\n"
            "101 Introduction to Computing I, 3\n"
            "(Information of the course)...\n\n"
            "220 Another Comp Class I, 3\n"
            "(Information)... ")

matches = regex.finditer(pattern, test_str)
results = []
firstGroup = None

for matchNum, match in enumerate(matches, start=1):
    if match.group(1) is not None:
        firstGroup = match.group(1)

    tempList = [firstGroup]
    for groupNum in range(1, len(match.groups())):
        groupNum = groupNum + 1
        tempList.append(match.group(groupNum))
    results.append(tempList)
print(results)

输出

[['CSC', '201', 'Introduction to Computing', '3'], ['CSC', '220', 'Another Comp Class', '3'], ['CSC', '101', 'Introduction to Computing', '3'], ['CSC', '220', 'Another Comp Class', '3']]

推荐阅读