from docx import Document
= "这里是科室名称"
dept_name = "这里是主诉"
major_complaint
= {'dept-name': dept_name,
replacemen_dict 'major-complaint': major_complaint,
}
= Document('data/结构化病历模板-入院记录.docx')
doc
# 替换页眉中的占位符
for section in doc.sections:
= section.header
header for pg in header.paragraphs:
if "{{dept-name}}" in pg.text:
= pg.text.replace("{{dept-name}}", dept_name)
pg.text
# 替换段落中的占位符
for placeholder, replace_text in replacemen_dict.items():
for pg in doc.paragraphs:
# print(pg.text)
# print(f"{{{{{placeholder}}}}}")
if f"{{{{{placeholder}}}}}" in pg.text:
= pg.text.replace(f"{{{{{placeholder}}}}}", replace_text)
pg.text
'data/output.docx') doc.save(
51 Python-docx
51.1 占位符替换
页眉和正文的文本对象不同
51.1.1 页眉和正文的普通文本
51.1.2 正文的特殊字符
比如复选框,单选框等
from docx import Document
= Document('data/demo-template.docx')
doc
# 遍历文档中的所有 paragraph 和 run
for paragraph in doc.paragraphs:
for run in paragraph.runs:
# 检查 run 中是否包含占位符
if "{复选框已选中状态}" in run.text:
# 获取占位符的索引
= run.text.find("{复选框已选中状态}")
index
# 替换占位符为复选框(使用Unicode字符)
= run.text.replace("{复选框已选中状态}", "")
run.text
# 在占位符位置后插入选中状态的复选框(使用Unicode字符)
u'\u2611') # Unicode字符:☑
run.add_text(
# 保存文档
"data/demo.docx") doc.save(
51.1.3 表格中的占位符
前提是保证点位符属于同一个运行(run),可以采用对连续字符应用样式。这里因为,: 如果字符是连续的并且具有相同的格式,则它们通常会被包含在同一个运行中。例如,如果您在Word中键入一段文字并对其应用相同的字体、字号和颜色,则这些字符通常会被视为同一个运
import json
with open('data/json_path_value_dict.json', 'r', encoding='utf-8') as f:
= json.load(f)
json_data
json_data
{'input-text-number.GBS-Score.sbp-score.name': '收缩压得分',
'input-text-number.GBS-Score.sbp-score.value': 2,
'input-text-number.GBS-Score.sbun-score.name': '血尿素氮得分',
'input-text-number.GBS-Score.sbun-score.value': 2,
'input-text-number.GBS-Score.hgb-m-score.name': '血红蛋白得分-男',
'input-text-number.GBS-Score.hgb-m-score.value': None,
'input-text-number.GBS-Score.hgb-f-score.name': '血红蛋白得分-女',
'input-text-number.GBS-Score.hgb-f-score.value': None,
'input-text-number.GBS-Score.hgb-score.name': '血红蛋白得分',
'input-text-number.GBS-Score.hgb-score.value': 3,
'input-text-number.GBS-Score.other-signs-score.name': '其他表现得分',
'input-text-number.GBS-Score.other-signs-score.value': 2,
'input-text-number.GBS-Score.total-score.name': 'GBS评分总分',
'input-text-number.GBS-Score.total-score.value': 9,
'input-text-number.ROCKALL-Score.age-score.name': '年龄得分',
'input-text-number.ROCKALL-Score.age-score.value': 1,
'input-text-number.ROCKALL-Score.shock-score.name': '休克状况得分',
'input-text-number.ROCKALL-Score.shock-score.value': 2,
'input-text-number.ROCKALL-Score.combordity-score.name': '伴发疾病得分',
'input-text-number.ROCKALL-Score.combordity-score.value': 0,
'input-text-number.ROCKALL-Score.endoscopy-sign-score.name': '内镜诊断得分',
'input-text-number.ROCKALL-Score.endoscopy-sign-score.value': None,
'input-text-number.ROCKALL-Score.recent-bleeding-sign-score.name': '近期出血征象得分',
'input-text-number.ROCKALL-Score.recent-bleeding-sign-score.value': None,
'input-text-number.ROCKALL-Score.total-score.name': 'ROCKALL评分总分',
'input-text-number.ROCKALL-Score.total-score.value': 3,
'input-text-number.detail-table.doctor.name': '主管医生',
'input-text-number.detail-table.doctor.value': None,
'input-text-number.detail-table.name.name': '姓名',
'input-text-number.detail-table.name.value': None,
'input-text-number.detail-table.age.name': '年龄',
'input-text-number.detail-table.age.value': None,
'input-text-number.detail-table.patid.name': '住院号',
'input-text-number.detail-table.patid.value': None,
'input-text-number.detail-table.icu-stay.name': 'ICU住院日',
'input-text-number.detail-table.icu-stay.value': None,
'input-text-number.detail-table.gbs-score.name': 'GBS评分',
'input-text-number.detail-table.gbs-score.value': 2,
'input-text-number.detail-table.rockall-score.name': 'ROCKALL评分',
'input-text-number.detail-table.rockall-score.value': 3,
'input-text-number.detail-table.blood-report-time.name': '血常规报告时间',
'input-text-number.detail-table.blood-report-time.value': 7,
'input-text-number.detail-table.aptt-report-time.name': '止凝血报告时间',
'input-text-number.detail-table.aptt-report-time.value': 10,
'input-text-number.detail-table.chemistry-report-time.name': '生化报告时间',
'input-text-number.detail-table.chemistry-report-time.value': 1,
'input-text-number.detail-table.first-blood-bag-time.name': '第1袋发血时间',
'input-text-number.detail-table.first-blood-bag-time.value': 9,
'input-text-number.detail-table.gastric-department-consult-time.name': '消化内科会诊时间',
'input-text-number.detail-table.gastric-department-consult-time.value': 17,
'input-text-number.detail-table.mdt-time.name': 'MDT时间',
'input-text-number.detail-table.mdt-time.value': 4,
'input-text-number.detail-table.endoscopy-arrival-time.name': '胃镜到达现场时间',
'input-text-number.detail-table.endoscopy-arrival-time.value': 2,
'input-text-number.detail-table.ulcer-site.name': '溃疡部位',
'input-text-number.detail-table.ulcer-site.value': None,
'input-text-number.detail-table.other-endoscopy-view.name': '其他胃镜结果',
'input-text-number.detail-table.other-endoscopy-view.value': None,
'input-text-number.detail-table.bed-endoscopy-duration.name': '床旁胃镜时间',
'input-text-number.detail-table.bed-endoscopy-duration.value': 2,
'input-text-number.detail-table.red-blood-cell-infusion-units.name': '输红细胞总量',
'input-text-number.detail-table.red-blood-cell-infusion-units.value': 1,
'input-text-number.detail-table.plasma-infusion-volume.name': '输血浆总量',
'input-text-number.detail-table.plasma-infusion-volume.value': 0,
'input-text-number.detail-table.platelet-infusion-volume.name': '输血小板总量',
'input-text-number.detail-table.platelet-infusion-volume.value': 2,
'input-text-number.detail-table.cold-precipitation-volume.name': '输冷沉淀总量',
'input-text-number.detail-table.cold-precipitation-volume.value': 30,
'input-text-number.detail-table.fibrinogen-infusion-volume.name': '输纤维蛋白原总量',
'input-text-number.detail-table.fibrinogen-infusion-volume.value': 1.5,
'input-text-number.detail-table.acid-suppressor-name.name': '抑酸药物名称',
'input-text-number.detail-table.acid-suppressor-name.value': '拉唑',
'input-text-number.detail-table.surgery-name.name': '外科手术名称',
'input-text-number.detail-table.surgery-name.value': '胃大部切除',
'input-text-number.detail-table.intervention-name.name': '介入手术名称',
'input-text-number.detail-table.intervention-name.value': '介入栓塞',
'input-text-number.detail-table.utlimate-confirmed-bleeding-site.name': '最终诊断出血部分',
'input-text-number.detail-table.utlimate-confirmed-bleeding-site.value': None,
'input-text-number.detail-table.department-transferred-for.name': '转出科室名称',
'input-text-number.detail-table.department-transferred-for.value': None,
'input-text-number.detail-table.total-fee.name': '总费用',
'input-text-number.detail-table.total-fee.value': 5064.36,
'radio-group.GBS-Score.sbp-value.name': '收缩压值',
'radio-group.GBS-Score.sbp-value.value': '2分:90 ~ 100',
'radio-group.GBS-Score.sbun-value.name': '血尿素氮值',
'radio-group.GBS-Score.sbun-value.value': '2分:6.5 ~ 7.9',
'radio-group.GBS-Score.hgb-m-value.name': '血红蛋白值-男',
'radio-group.GBS-Score.hgb-m-value.value': '3分:110 ~ 119',
'radio-group.GBS-Score.hgb-f-value.name': '血红蛋白值-女',
'radio-group.GBS-Score.hgb-f-value.value': None,
'radio-group.GBS-Score.risk-category.name': 'GBS评分危险度分级',
'radio-group.GBS-Score.risk-category.value': '≥6分:中高危',
'radio-group.ROCKALL-Score.age-value.name': '年龄值',
'radio-group.ROCKALL-Score.age-value.value': '1分:60 ~ 79',
'radio-group.ROCKALL-Score.shock-value.name': '休克状况值',
'radio-group.ROCKALL-Score.shock-value.value': '2分:低血压(收缩压<100mmHg,心率≥100次/分)',
'radio-group.ROCKALL-Score.recent-bleeding-sign.name': '近期出血征象',
'radio-group.ROCKALL-Score.recent-bleeding-sign.value': None,
'radio-group.ROCKALL-Score.risk-category.name': 'ROCKALL评分危险度分级',
'radio-group.ROCKALL-Score.risk-category.value': '3~4分:中危',
'radio-group.detail-table.patient-source.name': '病人来源',
'radio-group.detail-table.patient-source.value': '普通病房',
'radio-group.detail-table.gbs-risk.name': 'GBS风险分级',
'radio-group.detail-table.gbs-risk.value': '低危',
'radio-group.detail-table.rockall-risk.name': 'ROCKALL风险分级',
'radio-group.detail-table.rockall-risk.value': '中危',
'radio-group.detail-table.intubation.name': '气管插管',
'radio-group.detail-table.intubation.value': '是',
'radio-group.detail-table.cvc.name': '深静脉置管',
'radio-group.detail-table.cvc.value': '是',
'radio-group.detail-table.bedside-endoscopy.name': '床旁胃镜',
'radio-group.detail-table.bedside-endoscopy.value': '否',
'radio-group.detail-table.808-schema.name': '是否采用808方案',
'radio-group.detail-table.808-schema.value': '是',
'radio-group.detail-table.eddoscropy-over-time.name': '胃镜完善时间',
'radio-group.detail-table.eddoscropy-over-time.value': '2小时内',
'radio-group.detail-table.surgery-initialization-time.name': '手术时间',
'radio-group.detail-table.surgery-initialization-time.value': '24小时内',
'radio-group.detail-table.intervention-initialization-time.name': '介入时间',
'radio-group.detail-table.intervention-initialization-time.value': '24小时内',
'radio-group.detail-table.post-care-rebleeding.name': '治疗再出血',
'radio-group.detail-table.post-care-rebleeding.value': '是',
'check.GBS-Score.other-signs-pulse.name': '其他表现-脉搏',
'check.GBS-Score.other-signs-pulse.value': 1,
'check.GBS-Score.other-signs-black-stools.name': '其他表现-黑便',
'check.GBS-Score.other-signs-black-stools.value': 1,
'check.GBS-Score.other-signs-faintness.name': '其他表现-晕厥',
'check.GBS-Score.other-signs-faintness.value': False,
'check.GBS-Score.other-signs-liver-disease.name': '其他表现-肝病',
'check.GBS-Score.other-signs-liver-disease.value': False,
'check.GBS-Score.other-signs-heart-failure.name': '其他表现-心衰',
'check.GBS-Score.other-signs-heart-failure.value': False,
'check.ROCKALL-Score.combordity-none.name': '伴发疾病-无',
'check.ROCKALL-Score.combordity-none.value': 1,
'check.ROCKALL-Score.combordity-heart.name': '伴发疾病-心衰',
'check.ROCKALL-Score.combordity-heart.value': 0,
'check.ROCKALL-Score.combordity-liver-kidney-tumor.name': '伴发疾病-肝肾肿瘤',
'check.ROCKALL-Score.combordity-liver-kidney-tumor.value': 0,
'check.ROCKALL-Score.endoscopy-sign-none.name': '内镜诊断-无',
'check.ROCKALL-Score.endoscopy-sign-none.value': False,
'check.ROCKALL-Score.endoscopy-sign-ulcer.name': '内镜诊断-溃疡',
'check.ROCKALL-Score.endoscopy-sign-ulcer.value': False,
'check.ROCKALL-Score.endoscopy-sign-tumor.name': '内镜诊断-肿瘤',
'check.ROCKALL-Score.endoscopy-sign-tumor.value': False,
'check.ROCKALL-Score.recent-bleeding-sign-none.name': '近期出血征象-无',
'check.ROCKALL-Score.recent-bleeding-sign-none.value': False,
'check.ROCKALL-Score.recent-bleeding-sign-exist.name': '近期出血征象-有',
'check.ROCKALL-Score.recent-bleeding-sign-exist.value': False,
'check.detail-table.mdt-yes.name': 'MDT-是',
'check.detail-table.mdt-yes.value': 1,
'check.detail-table.mdt-no.name': 'MDT-否',
'check.detail-table.mdt-no.value': 1,
'check.detail-table.endoscopy-site-room.name': '胃镜检查地点-胃镜室',
'check.detail-table.endoscopy-site-room.value': 1,
'check.detail-table.endoscopy-site-bedside.name': '胃镜检查地点-床边',
'check.detail-table.endoscopy-site-bedside.value': 1,
'check.detail-table.endoscopy-view-varicose-veins.name': '胃镜检查结果-静脉曲张',
'check.detail-table.endoscopy-view-varicose-veins.value': 1,
'check.detail-table.endoscopy-view-varicose-veins-esophagus.name': '胃镜检查结果-静脉曲张-食管',
'check.detail-table.endoscopy-view-varicose-veins-esophagus.value': 1,
'check.detail-table.endoscopy-view-varicose-veins-fundus.name': '胃镜检查结果-静脉曲张-胃底',
'check.detail-table.endoscopy-view-varicose-veins-fundus.value': 1,
'check.detail-table.endoscopy-view-ulcer.name': '胃镜检查结果-溃疡',
'check.detail-table.endoscopy-view-ulcer.value': 1,
'check.detail-table.endoscopy-view-others.name': '胃镜检查结果-其他',
'check.detail-table.endoscopy-view-others.value': 1,
'check.detail-table.outcome-discharge.name': '患者转归-出院',
'check.detail-table.outcome-discharge.value': 1,
'check.detail-table.outcome-transfer.name': '患者转归-转科',
'check.detail-table.outcome-transfer.value': 1,
'check.detail-table.outcome-death.name': '患者转归-死亡',
'check.detail-table.outcome-death.value': 1,
'date-time.detail-table.in-datetime.name': '入科日期',
'date-time.detail-table.in-datetime.value': False,
'date-time.detail-table.out-datetime.name': '出科时间',
'date-time.detail-table.out-datetime.value': False,
'key': 'f1d9beae-f215-42c5-b305-8db672d76809',
'table_name': '消化道出血病人列表的每个病人的数据详情',
'dept': '重症医学科三区',
'patid': '1027386',
'name': '林文海',
'submit_time': '2024-05-14 16:10:42',
'link_key': '9c79ec44-2f2d-4255-9914-ca6967b7d0e8',
'gender': '男',
'age': 56}
from docx import Document
import re
= Document('data/gastric-bleeding-score-template-with-placedholders.docx')
doc
= r'\{[a-zA-Z-_.]+@{0,}.*?\}'
json_path_pattern
# 读取文档中的所有表格
for table in doc.tables:
for row in table.rows:
for cell in row.cells:
# 遍历单元格中的所有段落
for paragraph in cell.paragraphs:
# 遍历段落中的所有运行并打印文本内容
for run in paragraph.runs:
# print(f"run.text: {run.text}")
= re.findall(json_path_pattern, run.text)
matched if matched:
# print(f"matched: {matched}")
for placeholder in matched:
# 在json_data中的键
= placeholder.strip('{}')
placeholder_key
# 获取替换值
= json_data.get(placeholder_key, '')
placeholder_replacement
# 如果为None或者False
if not placeholder_replacement:
= ''
placeholder_replacement
# 全部转换为字符型
= str(placeholder_replacement)
placeholder_replacement
# 处理复选框
if 'check.' in placeholder:
if placeholder_replacement == "1":
= u'\u2611' # 复选模式选中状态
placeholder_replacement else:
= u'\u2610' # 复选模式未选中状态
placeholder_replacement
# 处理单选框
if 'radio-group.' in placeholder:
# radio-group的占位符比较特殊,需要调整下,如: {radio-group.detail-table.patient-source.value@急诊},即将选中时对应的value放在@后面
# 调整placeholder_key
= placeholder_key.split("@")
placeholder_key, placeholder_radio_value
# 获取替换值
= json_data.get(placeholder_key, '')
placeholder_replacement
if placeholder_replacement == placeholder_radio_value:
= u'\u2611' # 复选模式选中状态
placeholder_replacement else:
= u'\u2610' # 复选模式未选中状态
placeholder_replacement
# 也可设置为单选框未选中状态的字符
print(f"\n\nrun.text: {run.text}, \
placeholder: {placeholder}, \
placeholder_key: {placeholder_key}, \
placeholder_replacement: {placeholder_replacement}")
= run.text.replace(placeholder, placeholder_replacement)
run.text
# 保存文档
"data/gastric-bleeding-score.docx") doc.save(
run.text: {dept}危险性上消化道出血病人资料表, placeholder: {dept}, placeholder_key: dept, placeholder_replacement: 重症医学科三区
run.text: {date-time.detail-table.in-datetime.value}, placeholder: {date-time.detail-table.in-datetime.value}, placeholder_key: date-time.detail-table.in-datetime.value, placeholder_replacement:
run.text: {input-text-number.detail-table.doctor.value}, placeholder: {input-text-number.detail-table.doctor.value}, placeholder_key: input-text-number.detail-table.doctor.value, placeholder_replacement:
run.text: 姓名:{input-text-number.detail-table.name.value} 性别:{gender} 年龄:{age} 住院号:{patid} , placeholder: {input-text-number.detail-table.name.value}, placeholder_key: input-text-number.detail-table.name.value, placeholder_replacement:
run.text: 姓名: 性别:{gender} 年龄:{age} 住院号:{patid} , placeholder: {gender}, placeholder_key: gender, placeholder_replacement: 男
run.text: 姓名: 性别:男 年龄:{age} 住院号:{patid} , placeholder: {age}, placeholder_key: age, placeholder_replacement: 56
run.text: 姓名: 性别:男 年龄:56 住院号:{patid} , placeholder: {patid}, placeholder_key: patid, placeholder_replacement: 1027386
run.text: {radio-group.detail-table.patient-source.value@急诊} , placeholder: {radio-group.detail-table.patient-source.value@急诊}, placeholder_key: radio-group.detail-table.patient-source.value, placeholder_replacement: ☐
run.text: {radio-group.detail-table.patient-source.value@外院转诊} , placeholder: {radio-group.detail-table.patient-source.value@外院转诊}, placeholder_key: radio-group.detail-table.patient-source.value, placeholder_replacement: ☐
run.text: {radio-group.detail-table.patient-source.value@普通病房}, placeholder: {radio-group.detail-table.patient-source.value@普通病房}, placeholder_key: radio-group.detail-table.patient-source.value, placeholder_replacement: ☑
run.text: {check.detail-table.outcome-death.value}, placeholder: {check.detail-table.outcome-death.value}, placeholder_key: check.detail-table.outcome-death.value, placeholder_replacement: ☑