+
36
-

回答

通过 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')来选择使用哪种分离方式,使代码更具通用性。

网友回复

我知道答案,我要回答