通过 python-docx 这个强大的库,我们可以读取文档的结构、文本内容以及格式信息(如高亮、颜色等),从而实现将试卷和答案分离的目标。
这个任务的核心是确定一个可靠的规则来区分“题目”和“答案”。您提到的“标注文本”是关键。在Word中,常见的标注方法有:
高亮颜色 (Highlight Color):给答案文本设置一个背景色(如黄色)。
字体颜色 (Font Color):将答案文本的颜色设置为不同于题目的颜色(如红色)。
特定标记 (Keywords):在答案前后使用固定的关键词,如 【答案】 或 (Answer)。
下面我将提供两种最常用、最可靠的方案(基于高亮和字体颜色),并附上完整的Python代码。
准备工作
首先,你需要安装 python-docx 库。
pip install python-docx
然后,准备一个Word文档作为示例,我们命名为 sample_paper.docx。在这个文档里,我们用高亮或者红色字体来标记答案。
方案一:根据“高亮颜色”分离
这是最推荐的方法,因为它通常不会与题目本身的格式(如加粗、斜体)冲突。
逻辑思路:
遍历文档中的每一个段落(Paragraph)。
在每个段落中,遍历每一个文本块(Run)。一个“Run”是具有相同格式的连续文本。
检查每个Run是否有高亮颜色。
创建两个新的Word文档:一个用于试卷,一个用于答案。
将非高亮的Run(题目部分)同时写入试卷和答案文档。
将高亮的Run(答案部分)只写入答案文档。对于试卷文档,可以在对应位置留空或添加下划线 (____)。
Python代码实现:
from docx import Document from docx.enum.text import WD_COLOR_INDEX def copy_run_format(source_run, target_run): """复制一个Run的格式(字体、大小、加粗、斜体等)""" target_run.bold = source_run.bold target_run.italic = source_run.italic target_run.underline = source_run.underline target_run.font.name = source_run.font.name target_run.font.size = source_run.font.size target_run.font.color.rgb = source_run.font.color.rgb def separate_by_highlight(source_path, paper_path, key_path): """ 根据高亮颜色分离试卷和答案。 - source_path: 原始Word文档路径 - paper_path: 生成的试卷文件路径 - key_path: 生成的答案文件路径 """ source_doc = Document(source_path) paper_doc = Document() key_doc = Document() print(f"开始处理文档: {source_path}") for para in source_doc.paragraphs: # 为两个新文档创建新段落 paper_p = paper_doc.add_paragraph() key_p = key_doc.add_paragraph() # 复制原段落的格式(如对齐方式) paper_p.paragraph_format.alignment = para.paragraph_format.alignment key_p.paragraph_format.alignment = para.paragraph_format.alignment # 标记当前段落是否包含答案 has_answer_in_para = any( run.font.highlight_color is not None and run.font.highlight_color != WD_COLOR_INDEX.AUTO for run in para.runs ) for run in para.runs: # 检查当前run是否是高亮(答案) is_answer = run.font.highlight_color is not None and run.font.highlight_color != WD_COLOR_INDEX.AUTO if is_answer: # 如果是答案,则只写入答案文档,并保留其原始格式 key_run = key_p.add_run(run.text) copy_run_format(run, key_run) # 答案部分也恢复正常背景色 key_run.font.highlight_color = WD_COLOR_INDEX.AUTO else: # 如果是题目,则同时写入试卷和答案文档 paper_run = paper_p.add_run(run.text) copy_run_format(run, paper_run) key_run = key_p.add_run(run.text) copy_run_format(run, key_run) # 如果段落中包含答案,在试卷的相应段落末尾添加括号用于填写 if has_answer_in_para: paper_p.add_run(" (____)") paper_doc.save(paper_path) key_doc.save(key_path) print(f"处理完成!\n试卷已保存至: {paper_path}\n答案已保存至: {key_path}") # --- 使用示例 --- if __name__ == "__main__": # 假设你的Word文档叫 sample_paper.docx,并且答案用高亮标记 source_file = 'sample_paper.docx' output_paper_file = 'generated_paper.docx' output_key_file = 'generated_key.docx' separate_by_highlight(source_file, output_paper_file, output_key_file)
方案二:根据“字体颜色”分离
如果你的答案是用特定颜色(如红色)标记的,原理类似。
逻辑思路:与方案一基本相同,只是判断条件从 run.font.highlight_color 变为 run.font.color.rgb。
Python代码实现:
from docx import Document from docx.shared import RGBColor # copy_run_format 函数同上,这里省略 def separate_by_font_color(source_path, paper_path, key_path, answer_color=RGBColor(255, 0, 0)): """ 根据字体颜色分离试卷和答案。 - answer_color: 用于标记答案的RGB颜色,默认为红色。 """ source_doc = Document(source_path) paper_doc = Document() key_doc = Document() print(f"开始处理文档: {source_path}") for para in source_doc.paragraphs: paper_p = paper_doc.add_paragraph() key_p = key_doc.add_paragraph() paper_p.paragraph_format.alignment = para.paragraph_format.alignment key_p.paragraph_format.alignment = para.paragraph_format.alignment has_answer_in_para = any( run.font.color.rgb == answer_color for run in para.runs ) for run in para.runs: # 检查当前run的颜色是否是答案颜色 is_answer = run.font.color.rgb == answer_color if is_answer: key_run = key_p.add_run(run.text) copy_run_format(run, key_run) # 将答案的颜色恢复为黑色 key_run.font.color.rgb = RGBColor(0, 0, 0) else: paper_run = paper_p.add_run(run.text) copy_run_format(run, paper_run) key_run = key_p.add_run(run.text) copy_run_format(run, key_run) if has_answer_in_para: paper_p.add_run(" (____)") paper_doc.save(paper_path) key_doc.save(key_path) print(f"处理完成!\n试卷已保存至: {paper_path}\n答案已保存至: {key_path}") # --- 使用示例 --- if __name__ == "__main__": # 假设你的Word文档叫 sample_paper.docx,并且答案用红色字体标记 # from docx.shared import RGBColor # copy_run_format 函数需要放在这里或全局 source_file = 'sample_paper.docx' output_paper_file = 'generated_paper_by_color.docx' output_key_file = 'generated_key_by_color.docx' # 假设答案是红色 (R:255, G:0, B:0) separate_by_font_color(source_file, output_paper_file, output_key_file, answer_color=RGBColor(255, 0, 0))
重要提示和扩展
复杂文档:以上代码处理的是纯文本段落。如果你的Word文档中包含表格(Table)、图片(Image)或复杂的列表格式,代码需要进行扩展来处理这些元素。例如,你需要遍历表格中的单元格(cell)并对其中的段落应用相同的逻辑。
格式保持:copy_run_format 函数是为了尽可能多地保留原始格式。你可以根据需要添加更多格式的复制,例如字体效果(阴影、轮廓等)。
灵活性:你可以将这两个函数合并,通过一个 method 参数(如 'highlight' 或 'color')来选择使用哪种分离方式,使代码更具通用性。
网友回复