处理跨行的文本匹配失败的问题
This commit is contained in:
79
mcp_docx.py
79
mcp_docx.py
@@ -198,16 +198,77 @@ def replace_image(unpacked_dir, index, new_image_path):
|
|||||||
|
|
||||||
|
|
||||||
def paragraph_replace(para_el, replacements):
|
def paragraph_replace(para_el, replacements):
|
||||||
"""在 <w:t> 层面替换文本,完全不碰图片和格式"""
|
"""
|
||||||
for t_el in para_el.iter(f'{{{W}}}t'):
|
在段落级别替换文本,支持跨 <w:t> 元素的匹配。
|
||||||
if not t_el.text:
|
|
||||||
continue
|
策略:
|
||||||
new_text = t_el.text
|
1. 收集段落中所有 <w:t> 元素及其文本
|
||||||
|
2. 拼接成完整文本进行替换
|
||||||
|
3. 如果有替换发生,重新分配文本到原有的 <w:t> 元素中
|
||||||
|
"""
|
||||||
|
# 收集所有 run 元素(<w:r>),保持顺序
|
||||||
|
runs = list(para_el.findall(f'.//{{{W}}}r'))
|
||||||
|
if not runs:
|
||||||
|
return
|
||||||
|
|
||||||
|
# 收集所有文本元素及其位置信息
|
||||||
|
t_elements = []
|
||||||
|
for run in runs:
|
||||||
|
for t_el in run.findall(f'{{{W}}}t'):
|
||||||
|
t_elements.append((run, t_el))
|
||||||
|
|
||||||
|
if not t_elements:
|
||||||
|
return
|
||||||
|
|
||||||
|
# 拼接完整文本
|
||||||
|
full_text = ''.join(t_el.text or '' for _, t_el in t_elements)
|
||||||
|
original_text = full_text
|
||||||
|
|
||||||
|
# 执行所有替换
|
||||||
for old, new in replacements:
|
for old, new in replacements:
|
||||||
new_text = new_text.replace(old, new)
|
if old in full_text:
|
||||||
if new_text != t_el.text:
|
full_text = full_text.replace(old, new)
|
||||||
t_el.text = new_text
|
|
||||||
if new_text and (new_text[0] == ' ' or new_text[-1] == ' '):
|
# 如果没有变化,直接返回
|
||||||
|
if full_text == original_text:
|
||||||
|
return
|
||||||
|
|
||||||
|
print(f"段落替换: {len(original_text)} -> {len(full_text)} 字符")
|
||||||
|
|
||||||
|
# 将新文本重新分配到原有的 <w:t> 元素中
|
||||||
|
# 策略:尽量保持原有的文本分布比例
|
||||||
|
if len(t_elements) == 1:
|
||||||
|
# 只有一个 <w:t> 元素,直接替换
|
||||||
|
_, t_el = t_elements[0]
|
||||||
|
t_el.text = full_text
|
||||||
|
if full_text and (full_text[0] == ' ' or full_text[-1] == ' '):
|
||||||
|
t_el.set('{http://www.w3.org/XML/1998/namespace}space', 'preserve')
|
||||||
|
else:
|
||||||
|
# 多个 <w:t> 元素:按原始长度比例分配新文本
|
||||||
|
original_lengths = [len(t_el.text or '') for _, t_el in t_elements]
|
||||||
|
total_original = sum(original_lengths)
|
||||||
|
|
||||||
|
if total_original == 0:
|
||||||
|
# 原始都是空的,把所有文本放到第一个元素
|
||||||
|
t_elements[0][1].text = full_text
|
||||||
|
for i in range(1, len(t_elements)):
|
||||||
|
t_elements[i][1].text = ''
|
||||||
|
else:
|
||||||
|
# 按比例分配
|
||||||
|
pos = 0
|
||||||
|
for i, (_, t_el) in enumerate(t_elements):
|
||||||
|
if i == len(t_elements) - 1:
|
||||||
|
# 最后一个元素,取剩余所有文本
|
||||||
|
chunk = full_text[pos:]
|
||||||
|
else:
|
||||||
|
# 按比例计算应该分配的长度
|
||||||
|
ratio = original_lengths[i] / total_original
|
||||||
|
chunk_len = int(len(full_text) * ratio)
|
||||||
|
chunk = full_text[pos:pos + chunk_len]
|
||||||
|
pos += chunk_len
|
||||||
|
|
||||||
|
t_el.text = chunk
|
||||||
|
if chunk and (chunk[0] == ' ' or chunk[-1] == ' '):
|
||||||
t_el.set('{http://www.w3.org/XML/1998/namespace}space', 'preserve')
|
t_el.set('{http://www.w3.org/XML/1998/namespace}space', 'preserve')
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user