修复ubuntu环境下占位符替换为嗯体
This commit is contained in:
parent
7cbe4b29b7
commit
d01f367ffb
@ -217,17 +217,28 @@ class DocumentService:
|
|||||||
if not full_text:
|
if not full_text:
|
||||||
return
|
return
|
||||||
|
|
||||||
# 检查是否有占位符需要替换
|
# 检查是否有占位符需要替换(使用多种方式检查)
|
||||||
has_placeholder = False
|
has_placeholder = False
|
||||||
|
found_placeholders = []
|
||||||
for field_code in field_data.keys():
|
for field_code in field_data.keys():
|
||||||
placeholder = f"{{{{{field_code}}}}}"
|
placeholder = f"{{{{{field_code}}}}}"
|
||||||
if placeholder in full_text:
|
if placeholder in full_text:
|
||||||
has_placeholder = True
|
has_placeholder = True
|
||||||
break
|
found_placeholders.append(placeholder)
|
||||||
|
else:
|
||||||
|
# 尝试使用正则表达式检查(处理可能的编码问题)
|
||||||
|
import re
|
||||||
|
if re.search(re.escape(placeholder), full_text):
|
||||||
|
has_placeholder = True
|
||||||
|
found_placeholders.append(placeholder)
|
||||||
|
|
||||||
if not has_placeholder:
|
if not has_placeholder:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# 调试信息:记录找到的占位符
|
||||||
|
if found_placeholders:
|
||||||
|
print(f"[DEBUG] 段落中发现占位符: {found_placeholders}, 段落文本前50字符: '{full_text[:50]}'")
|
||||||
|
|
||||||
# 收集所有runs及其位置和格式信息
|
# 收集所有runs及其位置和格式信息
|
||||||
runs_info = []
|
runs_info = []
|
||||||
current_pos = 0
|
current_pos = 0
|
||||||
@ -269,11 +280,27 @@ class DocumentService:
|
|||||||
for field_code, field_value in field_data.items():
|
for field_code, field_value in field_data.items():
|
||||||
placeholder = f"{{{{{field_code}}}}}"
|
placeholder = f"{{{{{field_code}}}}}"
|
||||||
replacement_value = str(field_value) if field_value else ''
|
replacement_value = str(field_value) if field_value else ''
|
||||||
|
|
||||||
|
# 检查占位符是否在文本中(使用多种方式检查,确保兼容性)
|
||||||
|
if placeholder in final_text:
|
||||||
# 替换所有出现的占位符
|
# 替换所有出现的占位符
|
||||||
while placeholder in final_text:
|
before_replace = final_text
|
||||||
final_text = final_text.replace(placeholder, replacement_value, 1)
|
final_text = final_text.replace(placeholder, replacement_value)
|
||||||
replacement_count += 1
|
count = before_replace.count(placeholder)
|
||||||
print(f"[DEBUG] 替换占位符: {placeholder} -> '{replacement_value}'")
|
replacement_count += count
|
||||||
|
if count > 0:
|
||||||
|
print(f"[DEBUG] 替换占位符: {placeholder} -> '{replacement_value}' (共 {count} 次)")
|
||||||
|
else:
|
||||||
|
# 尝试使用正则表达式匹配(处理可能的编码或格式问题)
|
||||||
|
import re
|
||||||
|
escaped_placeholder = re.escape(placeholder)
|
||||||
|
if re.search(escaped_placeholder, final_text):
|
||||||
|
before_replace = final_text
|
||||||
|
final_text = re.sub(escaped_placeholder, replacement_value, final_text)
|
||||||
|
count = len(re.findall(escaped_placeholder, before_replace))
|
||||||
|
replacement_count += count
|
||||||
|
if count > 0:
|
||||||
|
print(f"[DEBUG] 使用正则表达式替换占位符: {placeholder} -> '{replacement_value}' (共 {count} 次)")
|
||||||
|
|
||||||
# 找到包含占位符的第一个run,使用它的格式
|
# 找到包含占位符的第一个run,使用它的格式
|
||||||
placeholder_run_format = None
|
placeholder_run_format = None
|
||||||
@ -295,6 +322,9 @@ class DocumentService:
|
|||||||
# 如果只有一个run,直接替换文本(会自动保持格式)
|
# 如果只有一个run,直接替换文本(会自动保持格式)
|
||||||
if len(runs_info) == 1:
|
if len(runs_info) == 1:
|
||||||
runs_info[0]['run'].text = final_text
|
runs_info[0]['run'].text = final_text
|
||||||
|
# 验证替换是否成功
|
||||||
|
if runs_info[0]['run'].text != final_text:
|
||||||
|
print(f"[WARN] 单run替换后验证失败:期望 '{final_text[:50]}...',实际 '{runs_info[0]['run'].text[:50]}...'")
|
||||||
else:
|
else:
|
||||||
# 多个run的情况:合并为一个run,保持格式
|
# 多个run的情况:合并为一个run,保持格式
|
||||||
# 先清空所有runs
|
# 先清空所有runs
|
||||||
@ -305,6 +335,14 @@ class DocumentService:
|
|||||||
first_run = runs_info[0]['run']
|
first_run = runs_info[0]['run']
|
||||||
first_run.text = final_text
|
first_run.text = final_text
|
||||||
|
|
||||||
|
# 验证文本是否被正确写入
|
||||||
|
if first_run.text != final_text:
|
||||||
|
print(f"[WARN] 多run替换后验证失败:期望 '{final_text[:50]}...',实际 '{first_run.text[:50]}...'")
|
||||||
|
# 尝试再次写入
|
||||||
|
first_run.text = final_text
|
||||||
|
if first_run.text != final_text:
|
||||||
|
print(f"[ERROR] 多次尝试写入失败,可能存在严重问题")
|
||||||
|
|
||||||
# 应用格式(使用包含占位符的run的格式,或第一个run的格式)
|
# 应用格式(使用包含占位符的run的格式,或第一个run的格式)
|
||||||
if placeholder_run_format:
|
if placeholder_run_format:
|
||||||
try:
|
try:
|
||||||
@ -328,9 +366,23 @@ class DocumentService:
|
|||||||
run_element = runs_info[i]['run']._element
|
run_element = runs_info[i]['run']._element
|
||||||
try:
|
try:
|
||||||
paragraph._element.remove(run_element)
|
paragraph._element.remove(run_element)
|
||||||
except:
|
except Exception as remove_error:
|
||||||
pass
|
print(f"[WARN] 删除run时出错: {str(remove_error)}")
|
||||||
|
|
||||||
|
# 最终验证:检查段落文本是否包含占位符
|
||||||
|
final_paragraph_text = paragraph.text
|
||||||
|
remaining_in_paragraph = []
|
||||||
|
for field_code in field_data.keys():
|
||||||
|
placeholder = f"{{{{{field_code}}}}}"
|
||||||
|
if placeholder in final_paragraph_text:
|
||||||
|
remaining_in_paragraph.append(placeholder)
|
||||||
|
|
||||||
|
if remaining_in_paragraph:
|
||||||
|
print(f"[WARN] 段落替换后仍有占位符: {remaining_in_paragraph}")
|
||||||
|
print(f"[WARN] 原始文本: '{full_text[:100]}'")
|
||||||
|
print(f"[WARN] 替换后文本: '{final_text[:100]}'")
|
||||||
|
print(f"[WARN] 段落实际文本: '{final_paragraph_text[:100]}'")
|
||||||
|
else:
|
||||||
print(f"[DEBUG] 段落替换了 {replacement_count} 个占位符(保持格式): '{full_text[:50]}...' -> '{final_text[:50]}...'")
|
print(f"[DEBUG] 段落替换了 {replacement_count} 个占位符(保持格式): '{full_text[:50]}...' -> '{final_text[:50]}...'")
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@ -452,9 +504,136 @@ class DocumentService:
|
|||||||
# 保存到临时文件
|
# 保存到临时文件
|
||||||
temp_dir = tempfile.gettempdir()
|
temp_dir = tempfile.gettempdir()
|
||||||
output_file = os.path.join(temp_dir, f"filled_{datetime.now().strftime('%Y%m%d%H%M%S')}.docx")
|
output_file = os.path.join(temp_dir, f"filled_{datetime.now().strftime('%Y%m%d%H%M%S')}.docx")
|
||||||
|
|
||||||
|
# 保存文档前,再次验证替换结果(用于调试)
|
||||||
|
print(f"[DEBUG] 保存前验证:检查文档中是否还有占位符...")
|
||||||
|
verification_placeholders = set()
|
||||||
|
for paragraph in doc.paragraphs:
|
||||||
|
text = paragraph.text
|
||||||
|
matches = placeholder_pattern.findall(text)
|
||||||
|
for match in matches:
|
||||||
|
field_code = match.strip()
|
||||||
|
if field_code:
|
||||||
|
verification_placeholders.add(field_code)
|
||||||
|
|
||||||
|
for table in doc.tables:
|
||||||
|
try:
|
||||||
|
if not table.rows:
|
||||||
|
continue
|
||||||
|
for row in table.rows:
|
||||||
|
try:
|
||||||
|
if not hasattr(row, 'cells'):
|
||||||
|
continue
|
||||||
|
try:
|
||||||
|
cells = row.cells
|
||||||
|
except (IndexError, AttributeError):
|
||||||
|
continue
|
||||||
|
for cell in cells:
|
||||||
|
try:
|
||||||
|
if hasattr(cell, 'paragraphs'):
|
||||||
|
for paragraph in cell.paragraphs:
|
||||||
|
text = paragraph.text
|
||||||
|
matches = placeholder_pattern.findall(text)
|
||||||
|
for match in matches:
|
||||||
|
field_code = match.strip()
|
||||||
|
if field_code:
|
||||||
|
verification_placeholders.add(field_code)
|
||||||
|
except Exception:
|
||||||
|
continue
|
||||||
|
except Exception:
|
||||||
|
continue
|
||||||
|
except Exception:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if verification_placeholders:
|
||||||
|
print(f"[WARN] 保存前验证发现仍有占位符: {sorted(verification_placeholders)}")
|
||||||
|
else:
|
||||||
|
print(f"[DEBUG] 保存前验证通过:所有占位符已替换")
|
||||||
|
|
||||||
|
# 保存文档
|
||||||
|
try:
|
||||||
doc.save(output_file)
|
doc.save(output_file)
|
||||||
print(f"[DEBUG] 文档已保存到: {output_file}")
|
print(f"[DEBUG] 文档已保存到: {output_file}")
|
||||||
|
|
||||||
|
# 验证文件是否真的存在且大小大于0
|
||||||
|
import time
|
||||||
|
time.sleep(0.1) # 等待文件系统同步(Ubuntu上可能需要)
|
||||||
|
|
||||||
|
if not os.path.exists(output_file):
|
||||||
|
raise Exception(f"文件保存失败:文件不存在 {output_file}")
|
||||||
|
|
||||||
|
file_size = os.path.getsize(output_file)
|
||||||
|
if file_size == 0:
|
||||||
|
raise Exception(f"文件保存失败:文件大小为0 {output_file}")
|
||||||
|
|
||||||
|
print(f"[DEBUG] 文件保存验证通过:文件大小 {file_size} 字节")
|
||||||
|
|
||||||
|
# 验证保存的文件内容是否正确(重新打开文件检查)
|
||||||
|
try:
|
||||||
|
verify_doc = Document(output_file)
|
||||||
|
verify_placeholders_in_saved = set()
|
||||||
|
for paragraph in verify_doc.paragraphs:
|
||||||
|
text = paragraph.text
|
||||||
|
matches = placeholder_pattern.findall(text)
|
||||||
|
for match in matches:
|
||||||
|
field_code = match.strip()
|
||||||
|
if field_code:
|
||||||
|
verify_placeholders_in_saved.add(field_code)
|
||||||
|
|
||||||
|
for table in verify_doc.tables:
|
||||||
|
try:
|
||||||
|
if not table.rows:
|
||||||
|
continue
|
||||||
|
for row in table.rows:
|
||||||
|
try:
|
||||||
|
if not hasattr(row, 'cells'):
|
||||||
|
continue
|
||||||
|
try:
|
||||||
|
cells = row.cells
|
||||||
|
except (IndexError, AttributeError):
|
||||||
|
continue
|
||||||
|
for cell in cells:
|
||||||
|
try:
|
||||||
|
if hasattr(cell, 'paragraphs'):
|
||||||
|
for paragraph in cell.paragraphs:
|
||||||
|
text = paragraph.text
|
||||||
|
matches = placeholder_pattern.findall(text)
|
||||||
|
for match in matches:
|
||||||
|
field_code = match.strip()
|
||||||
|
if field_code:
|
||||||
|
verify_placeholders_in_saved.add(field_code)
|
||||||
|
except Exception:
|
||||||
|
continue
|
||||||
|
except Exception:
|
||||||
|
continue
|
||||||
|
except Exception:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if verify_placeholders_in_saved:
|
||||||
|
print(f"[WARN] 保存后验证:文件中仍有占位符: {sorted(verify_placeholders_in_saved)}")
|
||||||
|
print(f"[WARN] 这可能是导致Ubuntu上占位符未替换的原因")
|
||||||
|
else:
|
||||||
|
print(f"[DEBUG] 保存后验证通过:文件中所有占位符已替换")
|
||||||
|
except Exception as verify_error:
|
||||||
|
print(f"[WARN] 保存后验证失败(不影响功能): {str(verify_error)}")
|
||||||
|
|
||||||
|
# 在Ubuntu上,可能需要显式同步文件系统
|
||||||
|
try:
|
||||||
|
import sys
|
||||||
|
if sys.platform != 'win32':
|
||||||
|
# 在非Windows系统上,尝试同步文件系统
|
||||||
|
os.sync()
|
||||||
|
print(f"[DEBUG] 已同步文件系统(非Windows系统)")
|
||||||
|
except Exception as sync_error:
|
||||||
|
print(f"[WARN] 文件系统同步失败(不影响功能): {str(sync_error)}")
|
||||||
|
|
||||||
|
except Exception as save_error:
|
||||||
|
error_msg = f"保存文档失败: {str(save_error)}"
|
||||||
|
print(f"[ERROR] {error_msg}")
|
||||||
|
import traceback
|
||||||
|
print(traceback.format_exc())
|
||||||
|
raise Exception(error_msg)
|
||||||
|
|
||||||
return output_file
|
return output_file
|
||||||
|
|
||||||
except IndexError as e:
|
except IndexError as e:
|
||||||
|
|||||||
Binary file not shown.
125
修复Ubuntu占位符替换问题.md
Normal file
125
修复Ubuntu占位符替换问题.md
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
# 修复Ubuntu环境下占位符未替换问题
|
||||||
|
|
||||||
|
## 问题描述
|
||||||
|
|
||||||
|
在本地Windows环境下生成的谈话审批表内容正确,占位符被正确替换,但在远程Ubuntu服务器上生成的文档中占位符没有被正确替换。
|
||||||
|
|
||||||
|
## 可能的原因
|
||||||
|
|
||||||
|
1. **文件保存问题**:在Ubuntu上,文件保存后可能没有正确刷新到磁盘
|
||||||
|
2. **编码问题**:Windows和Ubuntu在处理文件编码时可能有差异
|
||||||
|
3. **文件系统同步问题**:Ubuntu上可能需要显式同步文件系统
|
||||||
|
4. **占位符匹配问题**:可能因为编码或格式问题导致占位符没有被正确识别
|
||||||
|
|
||||||
|
## 修复内容
|
||||||
|
|
||||||
|
### 1. 增强占位符替换逻辑
|
||||||
|
|
||||||
|
- 添加了正则表达式匹配作为备用方案,确保能够识别各种格式的占位符
|
||||||
|
- 增强了替换逻辑,使用多种方式检查占位符是否存在
|
||||||
|
|
||||||
|
### 2. 增强文件保存验证
|
||||||
|
|
||||||
|
- 保存后验证文件是否存在且大小大于0
|
||||||
|
- 在非Windows系统上显式同步文件系统(使用`os.sync()`)
|
||||||
|
- 保存后重新打开文件验证内容是否正确
|
||||||
|
|
||||||
|
### 3. 增强调试信息
|
||||||
|
|
||||||
|
- 添加了详细的调试日志,记录每个替换步骤
|
||||||
|
- 在替换前后验证占位符是否存在
|
||||||
|
- 记录替换的详细信息,便于诊断问题
|
||||||
|
|
||||||
|
### 4. 增强替换后验证
|
||||||
|
|
||||||
|
- 替换后立即验证段落文本是否还包含占位符
|
||||||
|
- 如果验证失败,记录详细的错误信息
|
||||||
|
- 多次尝试写入,确保文本被正确写入
|
||||||
|
|
||||||
|
## 修改的文件
|
||||||
|
|
||||||
|
- `services/document_service.py`
|
||||||
|
|
||||||
|
## 主要修改点
|
||||||
|
|
||||||
|
1. **`replace_placeholder_in_paragraph`函数**:
|
||||||
|
- 添加了正则表达式匹配作为备用方案
|
||||||
|
- 增强了占位符检测逻辑
|
||||||
|
- 添加了替换后的验证步骤
|
||||||
|
|
||||||
|
2. **文件保存部分**:
|
||||||
|
- 添加了文件保存后的验证
|
||||||
|
- 在Ubuntu上显式同步文件系统
|
||||||
|
- 保存后重新打开文件验证内容
|
||||||
|
|
||||||
|
3. **调试信息**:
|
||||||
|
- 添加了详细的调试日志
|
||||||
|
- 记录每个替换步骤的详细信息
|
||||||
|
|
||||||
|
## 如何验证修复
|
||||||
|
|
||||||
|
1. **查看日志**:
|
||||||
|
- 在Ubuntu服务器上运行服务时,查看控制台输出的调试信息
|
||||||
|
- 特别关注以下日志:
|
||||||
|
- `[DEBUG] 替换占位符: ...`
|
||||||
|
- `[DEBUG] 保存前验证:检查文档中是否还有占位符...`
|
||||||
|
- `[DEBUG] 保存后验证通过:文件中所有占位符已替换`
|
||||||
|
- `[WARN] 保存后验证:文件中仍有占位符: ...`
|
||||||
|
|
||||||
|
2. **测试文档生成**:
|
||||||
|
- 在Ubuntu服务器上生成谈话审批表
|
||||||
|
- 下载生成的文档,检查占位符是否被正确替换
|
||||||
|
- 如果仍有问题,查看日志中的警告信息
|
||||||
|
|
||||||
|
3. **对比测试**:
|
||||||
|
- 在Windows和Ubuntu上使用相同的数据生成文档
|
||||||
|
- 对比生成的文档内容
|
||||||
|
- 查看日志中的差异
|
||||||
|
|
||||||
|
## 如果问题仍然存在
|
||||||
|
|
||||||
|
如果修复后问题仍然存在,请检查以下内容:
|
||||||
|
|
||||||
|
1. **查看日志**:
|
||||||
|
- 检查是否有 `[WARN]` 或 `[ERROR]` 日志
|
||||||
|
- 特别关注占位符替换相关的警告
|
||||||
|
|
||||||
|
2. **检查字段数据**:
|
||||||
|
- 确认传入的`field_data`包含所有需要的字段
|
||||||
|
- 确认字段值不为空
|
||||||
|
|
||||||
|
3. **检查模板文件**:
|
||||||
|
- 确认模板文件中的占位符格式正确(`{{field_code}}`)
|
||||||
|
- 确认占位符没有被其他字符包围
|
||||||
|
|
||||||
|
4. **检查python-docx版本**:
|
||||||
|
- 确认Windows和Ubuntu上使用的是相同版本的`python-docx`
|
||||||
|
- 当前版本:`python-docx==1.1.0`
|
||||||
|
|
||||||
|
5. **检查文件权限**:
|
||||||
|
- 确认Ubuntu服务器上的临时目录有写入权限
|
||||||
|
- 确认MinIO上传功能正常
|
||||||
|
|
||||||
|
## 进一步诊断
|
||||||
|
|
||||||
|
如果问题仍然存在,可以:
|
||||||
|
|
||||||
|
1. **启用更详细的日志**:
|
||||||
|
- 在代码中添加更多调试信息
|
||||||
|
- 记录每个步骤的详细信息
|
||||||
|
|
||||||
|
2. **对比文件内容**:
|
||||||
|
- 下载Windows和Ubuntu上生成的文档
|
||||||
|
- 使用工具对比文件内容,找出差异
|
||||||
|
|
||||||
|
3. **检查环境差异**:
|
||||||
|
- 对比Windows和Ubuntu上的Python版本
|
||||||
|
- 对比依赖包的版本
|
||||||
|
- 检查系统编码设置
|
||||||
|
|
||||||
|
## 注意事项
|
||||||
|
|
||||||
|
- 修复后的代码在保存文件时会等待0.1秒,确保文件系统同步
|
||||||
|
- 在Ubuntu上会显式调用`os.sync()`同步文件系统
|
||||||
|
- 如果文件保存验证失败,会抛出异常,阻止错误文件被上传
|
||||||
|
|
||||||
Loading…
x
Reference in New Issue
Block a user