如何用Python区分Word文档中的项目符号列表与编号列表?
Python-docx区分项目符号和编号列表的解决办法
问题核心
你的源文档里,编号和项目符号列表的段落样式全是List Paragraph,靠样式名根本分不出来;而且原代码还犯了低级错误——new_paragraph没定义就直接用,判断逻辑完全走不通,自然复制后格式乱套。
解决思路
别盯着段落样式名看,直接去读段落的列表编号底层属性(也就是Word XML里的numPr节点),通过这个节点就能区分是编号还是项目符号。
修正后的完整代码
import docx from docx.oxml.ns import qn my_doc = docx.Document() source_doc = docx.Document('source.docx') for para in source_doc.paragraphs: # 先复制段落文本和基础样式 new_para = my_doc.add_paragraph(para.text, style=para.style) # 复制字符级格式(比如加粗、字体、颜色这些) for run, new_run in zip(para.runs, new_para.runs): new_run.bold = run.bold new_run.italic = run.italic new_run.underline = run.underline new_run.font.name = run.font.name new_run.font.size = run.font.size new_run.font.color.rgb = run.font.color.rgb # 检查当前段落是不是列表项 num_pr = para._element.numPr if num_pr is not None: # 获取列表的编号ID和级别 num_id = num_pr.numId.val ilvl = num_pr.ilvl.val if hasattr(num_pr, 'ilvl') else 0 # 找到源文档对应的列表定义 num_def = source_doc.part.numbering_definitions._numbering.find(qn(f'w:num[@w:numId="{num_id}"]')) if num_def is not None: abstract_num_id = num_def.abstractNumId.val abstract_num = source_doc.part.numbering_definitions._numbering.find(qn(f'w:abstractNum[@w:abstractNumId="{abstract_num_id}"]')) if abstract_num is not None: lvl = abstract_num.find(qn(f'w:lvl[@w:ilvl="{ilvl}"]')) if lvl is not None: # 判断是项目符号还是编号 is_bullet = lvl.find(qn('w:bullet')) is not None is_number = lvl.find(qn('w:numFmt')) is not None if is_bullet: new_para.style = my_doc.styles['List Bullet'] elif is_number: new_para.style = my_doc.styles['List Number']
关键点说明
- 直接操作Word的XML底层节点
numPr,这才是存储列表类型的真实地方,比表面的样式名靠谱 - 通过
w:bullet节点判断项目符号,w:numFmt节点判断编号列表 - 顺便补上了字符格式的复制,确保复制的内容和源文档完全一致
- 修复了原代码里
new_paragraph未定义的致命错误
内容的提问来源于stack exchange,提问作者Jasleen Kaur
相关产品推荐
相关产品推荐

