# A类手动编号顺延 — 段落级 DEL/INS 模式 实战来源:CT维保合同-香花桥(2026-06-26)。新增"9. 第三方侵权"条款后,需将原9→10、10→11、11→12、12→13、13→14 顺延。所有条款编号均为手动文本(A类,run内w:t文字,无numPr)。 ## 核心模式 对每个需顺延的段落,找到包含旧编号的 run,用**段落级** DEL/INS 替换: ```python for old_num, new_num in renumber_map.items(): for r in p.findall(f'{{{W}}}r'): t = r.find(f'{{{W}}}t') if t is None or t.text is None: continue if t.text.strip().startswith(str(old_num)): # 1. DEL run: 旧编号 del_run = deepcopy(r) del_run.set(f'{{{W}}}rsidDel', rsid) del_t = del_run.find(f'{{{W}}}t') del_t.tag = f'{{{W}}}delText' del_t.text = str(old_num) del_w = etree.Element(f'{{{W}}}del') del_w.set(f'{{{W}}}id', str(nid)); nid += 1 del_w.set(f'{{{W}}}author', 'WB') del_w.set(f'{{{W}}}date', rev_date) del_w.append(del_run) # 2. INS run: 新编号 ins_run = deepcopy(r) ins_run.set(f'{{{W}}}rsidR', rsid) ins_t = ins_run.find(f'{{{W}}}t') ins_t.text = str(new_num) ins_w = etree.Element(f'{{{W}}}ins') ins_w.set(f'{{{W}}}id', str(nid)); nid += 1 ins_w.set(f'{{{W}}}author', 'WB') ins_w.set(f'{{{W}}}date', rev_date) ins_w.append(ins_run) # 3. 原 run 去掉编号前缀 t.text = t.text[len(str(old_num)):] # 4. DEL + INS 插入在原 run 之前 r.addprevious(ins_w) r.addprevious(del_w) break break # 每个段落只改一个编号 ``` ## 关键点 1. **DEL/INS 在段落级**(`w:p` 的直接子元素),不是 run 内 2. **从后往前处理**:如果用索引遍历,从后往前避免 offset 漂移 3. **只匹配run开头**:`t.text.strip().startswith(str(old_num))` 确保只匹配编号前缀 4. **原 run 保留剩余文本**:`t.text = t.text[len(str(old_num)):]` 去掉编号后保留标题文字 5. **ID 递增**:每个 DEL/INS 用独立 id,从 `max_id + 1` 起 ## 与 add_clause 的区别 - `add_clause` / `add_clause_before`:创建**全新段落**(整段 w:ins) - 本模式:修改**已有段落**的第一个 run 的编号,其余内容不动 ## 适用场景 - 新增条款后,后续**手动编号**(A类)的条款需要顺延 - 不适用于自动编号(B类)——自动编号由 number.xml 引擎处理,修改 run 内文字无效