69 lines
2.3 KiB
Markdown
69 lines
2.3 KiB
Markdown
# 表格单元格编辑:保持格式不被破坏
|
|
|
|
## 问题
|
|
|
|
编辑 docx 表格单元格中的文字时,两种常见错误做法都会破坏格式:
|
|
|
|
1. **`cell.paragraphs[0].clear()` + `add_run()`**:把多段结构压成一段,丢失加粗、字号、字体
|
|
2. **XML 层全 cell 文字重分片**:把修改后的文字均匀分配到所有 `w:t` 元素,破坏段落边界和编号
|
|
|
|
## 正确做法:段落级精确定位 + 只改目标段
|
|
|
|
```python
|
|
from docx import Document
|
|
from docx.shared import Pt
|
|
|
|
doc = Document('file.docx')
|
|
table = doc.tables[0]
|
|
cell = table.rows[7].cells[1]
|
|
|
|
# 1. 定位目标段落(按索引)
|
|
paras = cell.paragraphs
|
|
target_p = paras[4] # 例如 P4 是你要改的段落
|
|
|
|
# 2. 保存首 run 格式
|
|
first_run = target_p.runs[0]
|
|
saved = {
|
|
'name': first_run.font.name,
|
|
'size': first_run.font.size,
|
|
'bold': first_run.font.bold,
|
|
'italic': first_run.font.italic,
|
|
}
|
|
|
|
# 3. 文字替换
|
|
old_text = target_p.text
|
|
new_text = old_text.replace('要被替换的文字', '新文字')
|
|
|
|
# 4. 清空该段 → 重写(保留格式)
|
|
target_p.clear()
|
|
run = target_p.add_run(new_text)
|
|
run.font.name = saved['name']
|
|
run.font.size = saved['size']
|
|
run.font.bold = saved['bold']
|
|
run.font.italic = saved['italic']
|
|
|
|
# 5. 合并单元格:同步更新同行其他 cell
|
|
for col_idx in [2, 3]:
|
|
cell2 = table.rows[7].cells[col_idx]
|
|
p = cell2.paragraphs[4]
|
|
p.clear()
|
|
run = p.add_run(new_text)
|
|
run.font.name = saved['name']
|
|
run.font.size = saved['size']
|
|
|
|
doc.save('output.docx')
|
|
```
|
|
|
|
## 关键原则
|
|
|
|
- **不碰其他段落**:只改目标索引的段落,其余段落原封不动
|
|
- **不压多段为一段**:每个段落独立处理,保持 `P0/P1/P2/P3/P4` 结构不变
|
|
- **合并单元格全同步**:`row[7].cells[1]` 改了什么,`cells[2]`、`cells[3]` 也要同步
|
|
- **先读后改**:改前用 `cell.paragraphs[i].text` 确认内容,用 `cell.paragraphs[i].runs[0].font` 确认格式
|
|
|
|
## 本次教训
|
|
|
|
2026-06-26 预算绩效分析表:两轮都搞坏格式。
|
|
- 第一轮:`clear()` + `add_run()` 把 Row 7 的 P0-P10 多段结构压成一段
|
|
- 第二轮:XML 全 cell 文字重分片把 "2.成本核算分析" 变成 ".成本核算分析"(编号丢失)
|
|
- 第三轮(正确):定位到 P4(成本优化段),只改它,保留 P0-P3 不动 |