You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python操作docx:保留原格式高亮指定单词及段落拆分问题

问题分析

你的代码存在两个核心问题导致格式丢失:

  1. 处理though时,直接用paragraph.text提取纯文本,清空段落后重新添加的run默认使用文档基础样式(Arial、12号字),完全丢失了原段落中各部分的格式信息。
  2. 高亮global和over的逻辑是基于整个run的格式判断,而非针对单词本身,一旦run符合条件就修改整个run的格式,同时后续处理though的操作会覆盖之前的格式设置。
解决方案

要实现保留原格式的需求,需要针对run进行精细化拆分,只修改目标单词所在的小run,同时在拆分段落时复制原run的格式属性。

1. 高亮特定单词并保留原格式

遍历每个run,将包含目标单词的run拆分为「前缀+目标单词+后缀」三个部分,仅对目标单词的run设置高亮,前缀和后缀保留原run的格式。

2. 按though拆分段落并高亮

找到包含though的run后,拆分该run为多个部分,保留各部分的原格式,同时将though单独设为高亮,再将拆分后的内容重新组织为段落。

修正后的代码
from docx import Document
from docx.shared import RGBColor, Pt
from docx.enum.text import WD_COLOR_INDEX
import re

def highlight_specific_words(paragraph, target_words, color, highlight):
    """高亮段落中的指定单词,保留原格式"""
    new_runs = []
    for run in paragraph.runs:
        text = run.text
        # 遍历所有目标单词,拆分run
        for word in target_words:
            pattern = re.compile(rf'\b{re.escape(word)}\b')
            parts = pattern.split(text)
            if len(parts) <= 1:
                continue
            # 拆分后重新构建run
            current_pos = 0
            for part in parts:
                if part:
                    # 复制原run格式到新run
                    new_run = paragraph.add_run(part)
                    copy_run_format(run, new_run)
                    new_runs.append(new_run)
                    current_pos += len(part)
                # 如果不是最后一个部分,添加目标单词的高亮run
                if part != parts[-1]:
                    highlight_run = paragraph.add_run(word)
                    copy_run_format(run, highlight_run)
                    highlight_run.font.color.rgb = color
                    highlight_run.font.highlight_color = highlight
                    new_runs.append(highlight_run)
            # 原run处理完毕,跳过后续循环
            break
        else:
            # 如果run中没有目标单词,直接保留
            new_runs.append(run)
    # 清空原段落的run,替换为新构建的run
    paragraph.clear()
    for run in new_runs:
        paragraph._element.append(run._element)

def split_paragraph_by_word(paragraph, split_word, color, highlight):
    """按指定单词拆分段落并高亮该单词"""
    new_paragraphs = []
    current_text = []
    current_runs = []
    for run in paragraph.runs:
        text = run.text
        pattern = re.compile(rf'\b{re.escape(split_word)}\b')
        parts = pattern.split(text)
        if len(parts) <= 1:
            current_text.append(text)
            current_runs.append(run)
            continue
        # 处理第一个部分
        if parts[0]:
            temp_run = paragraph.add_run(parts[0])
            copy_run_format(run, temp_run)
            current_runs.append(temp_run)
        # 拆分出第一个段落(到split_word之前)
        first_paragraph = paragraph._parent.add_paragraph()
        for r in current_runs:
            first_paragraph._element.append(r._element)
        new_paragraphs.append(first_paragraph)
        # 添加高亮的split_word作为新段落的开头
        split_paragraph = paragraph._parent.add_paragraph()
        split_run = split_paragraph.add_run(split_word)
        copy_run_format(run, split_run)
        split_run.font.color.rgb = color
        split_run.font.highlight_color = highlight
        new_paragraphs.append(split_paragraph)
        # 处理剩余部分
        current_runs = []
        for part in parts[1:]:
            if part:
                temp_run = paragraph.add_run(part)
                copy_run_format(run, temp_run)
                current_runs.append(temp_run)
            if part != parts[-1]:
                # 如果还有split_word,继续拆分
                split_paragraph = paragraph._parent.add_paragraph()
                split_run = split_paragraph.add_run(split_word)
                copy_run_format(run, split_run)
                split_run.font.color.rgb = color
                split_run.font.highlight_color = highlight
                new_paragraphs.append(split_paragraph)
                current_runs = []
    # 添加最后一部分内容
    if current_runs:
        last_paragraph = paragraph._parent.add_paragraph()
        for r in current_runs:
            last_paragraph._element.append(r._element)
        new_paragraphs.append(last_paragraph)
    # 删除原段落
    paragraph._element.getparent().remove(paragraph._element)
    return new_paragraphs

def copy_run_format(source_run, target_run):
    """复制run的格式属性"""
    # 复制字体属性
    target_run.font.name = source_run.font.name
    target_run.font.size = source_run.font.size
    target_run.font.bold = source_run.font.bold
    target_run.font.italic = source_run.font.italic
    target_run.font.underline = source_run.font.underline
    # 复制颜色(如果原run有设置)
    if source_run.font.color.rgb:
        target_run.font.color.rgb = source_run.font.color.rgb
    # 复制高亮颜色(如果原run有设置)
    if source_run.font.highlight_color:
        target_run.font.highlight_color = source_run.font.highlight_color

# 主逻辑
document = Document("your_document.docx")

# 1. 高亮global(橙色文字+黄色高亮)和over(白色文字+绿色高亮)
highlight_specific_words(document.paragraphs[0], ["global"], RGBColor(255, 165, 0), WD_COLOR_INDEX.YELLOW)
highlight_specific_words(document.paragraphs[0], ["over"], RGBColor(255, 255, 255), WD_COLOR_INDEX.GREEN)

# 2. 按though拆分段落并高亮(白色文字+蓝色高亮)
split_paragraph_by_word(document.paragraphs[0], "though", RGBColor(255, 255, 255), WD_COLOR_INDEX.BLUE)

document.save("formatted_document.docx")
关键说明
  • copy_run_format函数负责复制原run的所有格式属性,确保拆分后的run保留原有的字体、字号、样式等。
  • highlight_specific_words函数通过拆分run来单独处理目标单词,避免修改整个run的格式。
  • split_paragraph_by_word函数在拆分段落时,会保留各部分的原格式,同时将though单独高亮并拆分为独立段落(可根据需求调整拆分逻辑,比如不拆分为新段落而是在同一段落内分隔)。

内容的提问来源于stack exchange,提问作者Dinesh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 23:53:21