Python中如何使用正则表达式提取考题文本结构化字段
Python正则提取考题字段最优实现
不要写单条超长正则硬匹配全字段,这是这类结构化文本提取最容易踩的坑——只要文本里多一个换行、一个HTML标签、一个多余空格,整条正则就直接失效,后续改规则也极其麻烦。最优实现是先预处理清格式、再按锚点切分单题、最后逐字段匹配,容错率和可维护性比单条正则高几个量级。
具体实现逻辑
- 文本预处理:先把所有HTML标签(比如示例里的
<p>、<a>)、连续换行/制表符/多余空格统一替换成单个空格,抹平格式差异,避免无关格式干扰匹配。 - 切分单题块:以
QUESTION NO:作为分割锚点,把整段长文本拆成独立的单道题目片段,从根源上避免跨题匹配的问题。 - 对每个单题块,用针对性的短正则分别提取目标字段:
- 题号:匹配
QUESTION NO:后的数字,正则为r'QUESTION NO:\s*(\d+)' - 题干文本:匹配题号结束后、第一个选项(
A./B.这类大写字母加句号开头的内容)之前的所有文本,正则用r'QUESTION NO:\s*\d+\s*(.*?)\s*(?=[A-Z]\.)',开非贪婪模式,匹配到第一个选项就停止 - 可选答案:匹配所有选项ID开头的片段,正则为
r'([A-Z])\.\s*(.*?)\s*(?=[A-Z]\.|Answer:)',匹配结果直接组装成{选项ID:选项内容}的字典 - 正确答案:匹配
Answer:后、Explanation:前的内容,正则为r'Answer:\s*([A-Z,\s]+)\s*(?=Explanation:)',拿到结果后按逗号分割就能得到正确答案列表 - 答案解析:匹配
Explanation:后的所有剩余内容,正则为r'Explanation:\s*(.*)$'
- 题号:匹配
可直接复用的代码
import re from typing import List, Dict def extract_exam_questions(raw_text: str) -> List[Dict]: # 清理HTML标签 clean_content = re.sub(r'<[^>]+>', '', raw_text) # 合并所有多余空白字符 clean_content = re.sub(r'\s+', ' ', clean_content).strip() # 按题号锚点切分单题 question_units = re.split(r'(?=QUESTION NO:\s*\d+)', clean_content) exam_result = [] for unit in question_units: if not unit.strip(): continue # 提取题号 qid_match = re.search(r'QUESTION NO:\s*(\d+)', unit) question_id = qid_match.group(1) if qid_match else '' # 提取题干 stem_match = re.search(r'QUESTION NO:\s*\d+\s*(.*?)\s*(?=[A-Z]\.)', unit) question_stem = stem_match.group(1).strip() if stem_match else '' # 提取所有选项 options = {} for opt in re.finditer(r'([A-Z])\.\s*(.*?)\s*(?=[A-Z]\.|Answer:)', unit): opt_id, opt_text = opt.groups() options[opt_id] = opt_text.strip() # 提取正确答案 ans_match = re.search(r'Answer:\s*([A-Z,\s]+)\s*(?=Explanation:)', unit) correct_answers = [a.strip() for a in ans_match.group(1).split(',')] if ans_match else [] # 提取解析 exp_match = re.search(r'Explanation:\s*(.*)$', unit) explanation = exp_match.group(1).strip() if exp_match else '' exam_result.append({ "题号": question_id, "题干文本": question_stem, "可选答案": options, "正确答案": correct_answers, "答案解析": explanation }) return exam_result # 调用示例 if __name__ == "__main__": # 替换为你的待处理原始文本即可 raw_text = """此处传入待处理的考题原始文本""" all_questions = extract_exam_questions(raw_text) for q in all_questions: print(q)
之前尝试的正则失效原因
你之前写的(?:QUESTION NO: )(\d+)(\w+)失效核心原因有两个:
\w+只能匹配连续的字母、数字、下划线,题干开头的空格、括号、特殊标点都无法匹配- 没有加非贪婪匹配和边界断言,匹配逻辑会无限制向后吞文本,直接打乱后续的题号匹配规则
内容的提问来源于stack exchange,提问作者Adam Chubbuck
相关产品推荐
相关产品推荐

