初始归档:健康管理资料库(大医网/药膳/体质监测/中医理论等12个资料集,7712个文件)
This commit is contained in:
commit
80ae3811cf
7712 files changed
+4628547
No files matched your search
@@ -0,0 +1,384 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
辅行诀五脏用药法要-药性探真 资料库 ETL 第 1 步(v3)
|
||||
01_来源数据 -> 02_加工数据
|
||||
|
||||
只做"数据清理",不做释义抽取 / 跨库关联 / 主题分析(用户 2026-09-15 指令)。
|
||||
|
||||
清理项:
|
||||
A 页面残留物:页眉(含缺书名号的嵌入形式)、独立页码、行尾空格、全角空格
|
||||
B 断行错位接合:段落被页眉/页码打断处自动接合
|
||||
C 形近错字 / 异体字 / 书名误字修正(逐条附核校依据)
|
||||
E 半角标点规范化(邻接汉字时)
|
||||
F 存疑登记:无法确证处不改动原文,逐条附疑正与核校来源
|
||||
|
||||
输出:
|
||||
02_加工数据/药性探真_第一章_清洗版.md
|
||||
02_加工数据/文本清洗报告.md (全部核对数据**按章/节列明**)
|
||||
02_加工数据/人工核对清单.md (按章/节列明的待人工确认项)
|
||||
02_加工数据/章节结构_第一章.json (清理配套定位索引)
|
||||
幂等:可重复运行,输出覆盖生成。
|
||||
"""
|
||||
import os, re, json, hashlib
|
||||
|
||||
BASE = os.path.expanduser("~/Documents/ai_agent_scraper_study/data/辅行诀五脏用药法要-药性探真")
|
||||
SRC = os.path.join(BASE, "01_来源数据/药性探真_第一章_原始_20260915.md")
|
||||
OUT_MD = os.path.join(BASE, "02_加工数据/药性探真_第一章_清洗版.md")
|
||||
OUT_REPORT = os.path.join(BASE, "02_加工数据/文本清洗报告.md")
|
||||
OUT_CHECK = os.path.join(BASE, "02_加工数据/人工核对清单.md")
|
||||
OUT_STRUCT = os.path.join(BASE, "02_加工数据/章节结构_第一章.json")
|
||||
|
||||
PAGE_HEADER_RE = re.compile(r'^\s*《?辅行诀五脏用药法要》?\s*药性探真\s*》?\s*$')
|
||||
PAGE_NUM_RE = re.compile(r'^\s*\d{1,3}\s*$')
|
||||
CJK = r'[\u4e00-\u9fff]'
|
||||
|
||||
# C 类:形近错字 / 异体字 / 书名误字(逐条核校)
|
||||
FIXES = [
|
||||
("先骋通使", "先聘通使", "《本经》牡桂条作「为诸药先聘通使」;下文自称「先聘」,本书自证"),
|
||||
("越洲山阴", "越州山阴", "陆佃籍贯,《宋史·陆佃传》作越州山阴"),
|
||||
("桜", "梫", "《纲目》桂条引《尔雅》「梫者,能侵害他木也」(梫,音寝)"),
|
||||
("国老之誊", "国老之誉", "文义:众药之王、和国老之誉;「誊」形近误"),
|
||||
("酒皰皷鼻", "酒疱皶鼻", "《本经》栀子条作「面赤,酒疱皶鼻」"),
|
||||
("淚出", "泪出", "异体字正字,全书他处均用「泪」"),
|
||||
("微字为蒼之讹字", "微字为苍之讹字", "《纲目》人参释名,简体正字"),
|
||||
("天元幻大论", "天元纪大论", "《素问》篇名作「天元纪大论」"),
|
||||
("白戸浆", "白酨浆", "酨即酢浆;《辅行诀》原书作「白酨浆」,本书小标题亦作白酨浆"),
|
||||
]
|
||||
|
||||
# F 类:存疑不改(原文保留)
|
||||
SUSPECT_RULES = [
|
||||
(r'菌,蕗。从竹,雨声', "《说文》「箘,箘簬。从竹,囷声。一曰博棋也」;疑「菌蕗」「雨声」为形近致误"),
|
||||
(r'大则性环详而缓', "《本草衍义》枳实条:「大则其性详而缓」,疑衍「环」字"),
|
||||
(r'决泄愤,地方但', "《本草衍义》:「皆取其疏通决泄、破结实之义。他方但导败风壅之气……」;"
|
||||
"此处「愤,地方但」疑为OCR丢字串行,待补正"),
|
||||
(r'由于积分布甚广', "据上下文(论枳之品种)疑当作「枳分布甚广」"),
|
||||
(r'传动产隻者为雄', "《竹谱》竹根雌雄辨:疑当作「其节单者为雄」(「隻」为「单」之误)"),
|
||||
(r'[((]?[))]', "原文含存疑符号(?),系作者或OCR存疑处,保留原文"),
|
||||
(r'[①②③④⑤⑥⑦⑧⑨⑩]', "脚注标记,对应脚注正文在本次来源中缺失,待补"),
|
||||
]
|
||||
|
||||
|
||||
def clean_text(raw: str):
|
||||
"""返回 (清洗文本, 事件列表, 删除统计)。事件均锚定到【清洗版行号】。"""
|
||||
recs = [] # [{"text":..., "fixes":[...], "punct":[...]}]
|
||||
removed = {"页眉": 0, "页码": 0}
|
||||
for line in raw.split("\n"):
|
||||
if PAGE_HEADER_RE.match(line):
|
||||
removed["页眉"] += 1
|
||||
continue
|
||||
if PAGE_NUM_RE.match(line):
|
||||
removed["页码"] += 1
|
||||
continue
|
||||
new = line.replace("\u3000", "").rstrip()
|
||||
rec = {"text": new, "fixes": [], "punct": []}
|
||||
for bad, good, why in FIXES:
|
||||
if bad in new:
|
||||
rec["fixes"].append({"原": bad, "改": good, "依据": why})
|
||||
new = new.replace(bad, good)
|
||||
# 保护「附录N」「第N章/节」后的分隔空格,避免与 OCR 断行空格一并折叠
|
||||
new = re.sub(r'(附录[一二三四五六七八九十]|第[一二三四五六七八九十]+[章节])[ \t]+',
|
||||
lambda m: m.group(1) + "\x01", new)
|
||||
prev = None
|
||||
while prev != new: # 中文词间半角空格(OCR断行残留)
|
||||
prev = new
|
||||
new = re.sub(r'(?<=[\u4e00-\u9fff])\s+(?=[\u4e00-\u9fff])', '', new)
|
||||
new = re.sub(r'(?<=[\u4e00-\u9fff])\s+(?=[,。、;:?!“”()《》])', '', new)
|
||||
new = re.sub(r'(?<=[,。、;:?!“”()《》])\s+(?=[\u4e00-\u9fff])', '', new)
|
||||
# E 类:半角标点 ↔ 全角(邻接汉字或全角标点)
|
||||
if re.search(CJK, line):
|
||||
for _pass in range(2): # 二次通过:括号先转全角后再判后随标点
|
||||
for asc, full in ((",", ","), (";", ";"), (":", ":"), ("?", "?"), ("!", "!")):
|
||||
new2 = re.sub(r'(?<=[\u4e00-\u9fff),。、;:?!”“》)])\s*' + re.escape(asc), full, new)
|
||||
if new2 != new:
|
||||
rec["punct"].append({"原": asc, "改": full}); new = new2
|
||||
for asc, full, side in (("(", "(", "后"), (")", ")", "前")):
|
||||
pat = (r'\s*' + re.escape(asc) + r'(?=' + CJK + r')') if side == "后" else \
|
||||
(r'(?<=' + CJK + r')\s*' + re.escape(asc))
|
||||
new2 = re.sub(pat, full, new)
|
||||
if new2 != new:
|
||||
rec["punct"].append({"原": asc, "改": full}); new = new2
|
||||
# 转换后再次折叠全角标点两侧空格
|
||||
new = re.sub(r'(?<=[\u4e00-\u9fff])\s+(?=[,。、;:?!“”()《》])', '', new)
|
||||
new = re.sub(r'(?<=[,。、;:?!“”()《》])\s+(?=[\u4e00-\u9fff])', '', new)
|
||||
new = re.sub(r'(?=[,。、;:?!])\s+', '', new)
|
||||
new = new.replace("\x01", " ") # 还原受保护的分隔空格
|
||||
rec["text"] = new.rstrip()
|
||||
recs.append(rec)
|
||||
|
||||
# 合并连续空行
|
||||
tmp = []
|
||||
prev_blank = False
|
||||
for r in recs:
|
||||
if r["text"] == "":
|
||||
if prev_blank:
|
||||
continue
|
||||
prev_blank = True
|
||||
else:
|
||||
prev_blank = False
|
||||
tmp.append(r)
|
||||
|
||||
# B 类:断行错位接合
|
||||
out, joins = [], []
|
||||
i = 0
|
||||
while i < len(tmp):
|
||||
cur = tmp[i]
|
||||
if (cur["text"] and not cur["text"].startswith("#") and len(cur["text"]) > 8
|
||||
and re.search(CJK + r'$', cur["text"])):
|
||||
j = i + 1
|
||||
while j < len(tmp) and tmp[j]["text"] == "":
|
||||
j += 1
|
||||
if j < len(tmp) and re.match(CJK, tmp[j]["text"]) and not tmp[j]["text"].startswith("#"):
|
||||
merged = {"text": cur["text"] + tmp[j]["text"],
|
||||
"fixes": cur["fixes"] + tmp[j]["fixes"],
|
||||
"punct": cur["punct"] + tmp[j]["punct"]}
|
||||
joins.append({"接合前": cur["text"][-20:], "接合后": tmp[j]["text"][:20],
|
||||
"_before_line": i + 1, "_cont_line": j + 1})
|
||||
out.append(merged)
|
||||
i = j + 1
|
||||
continue
|
||||
out.append(cur)
|
||||
i += 1
|
||||
|
||||
# 落定清洗版行号 + 事件汇总
|
||||
lines, events = [], []
|
||||
for n, rec in enumerate(out, start=1):
|
||||
lines.append(rec["text"])
|
||||
for f in rec["fixes"]:
|
||||
events.append(dict(类型="C形近错字", 行=n, **f))
|
||||
for p in rec["punct"]:
|
||||
events.append(dict(类型="E标点规范化", 行=n, 原=p["原"], 改=p["改"], 依据="半角标点邻接汉字"))
|
||||
for s in SUSPECT_RULES:
|
||||
for m in re.finditer(s[0], rec["text"]):
|
||||
events.append(dict(类型="F存疑", 行=n,
|
||||
原=f"…{rec['text'][max(0,m.start()-15):m.end()+15]}…", 改="(保留原文)", 依据=s[1]))
|
||||
for jn in joins:
|
||||
events.append(dict(类型="B断行接合", 行=jn["_before_line"],
|
||||
原=f"…{jn['接合前']} ‖ {jn['接合后']}…",
|
||||
改="接合为一段", 依据=f"段落被页眉/页码打断,接续于原第{jn['_cont_line']}行"))
|
||||
|
||||
text = re.sub(r'\n{3,}', '\n\n', "\n".join(lines)).strip() + "\n"
|
||||
# 去重:同行同类型同说明
|
||||
seen, uniq = set(), []
|
||||
for e in events:
|
||||
k = (e["类型"], e["行"], e["依据"])
|
||||
if k not in seen:
|
||||
seen.add(k); uniq.append(e)
|
||||
uniq.sort(key=lambda x: (x["行"], {"B断行接合": 0, "C形近错字": 1, "E标点规范化": 2, "F存疑": 3}[x["类型"]]))
|
||||
return text, uniq, removed
|
||||
|
||||
|
||||
def parse_structure(text: str):
|
||||
lines = text.split("\n")
|
||||
nodes = []
|
||||
for i, l in enumerate(lines, start=1):
|
||||
if not l.startswith("#"):
|
||||
continue
|
||||
title = l.lstrip("#").strip()
|
||||
if re.match(r'^第[一二三四五六七八九十]+章', title):
|
||||
lvl, typ = 1, "章"
|
||||
elif re.match(r'^第[一二三四五六七八九十]+节', title):
|
||||
lvl, typ = 2, "节"
|
||||
elif re.match(r'^(附[::]|\d+\.\s)', title):
|
||||
lvl, typ = 4, "附注"
|
||||
else:
|
||||
lvl, typ = 3, "条目"
|
||||
nodes.append({"标题": title, "起始行": i, "类型": typ, "_lvl": lvl})
|
||||
for n, node in enumerate(nodes):
|
||||
node["结束行"] = len(lines)
|
||||
for m in range(n + 1, len(nodes)):
|
||||
if nodes[m]["_lvl"] <= node["_lvl"]:
|
||||
node["结束行"] = nodes[m]["起始行"] - 1
|
||||
break
|
||||
GATE = {"辛": ("肝", "木", "春"), "咸": ("心", "火", "夏"), "甘": ("脾", "土", "长夏"),
|
||||
"酸": ("肺", "金", "秋"), "苦": ("肾", "水", "冬")}
|
||||
chapters = []
|
||||
for node in nodes:
|
||||
if node["类型"] == "章":
|
||||
chapters.append(dict(node, 节=[]))
|
||||
elif node["类型"] == "节":
|
||||
m = re.search(r'([辛咸甘酸苦])味?门', node["标题"])
|
||||
node["味门"] = m.group(1) if m else None
|
||||
if m:
|
||||
node["本脏"], node["本行"], node["脏象法象"] = GATE[m.group(1)]
|
||||
if chapters:
|
||||
chapters[-1]["节"].append(dict(node, 条目=[]))
|
||||
else:
|
||||
m = re.match(r'^[一二三四五六七八九十]+、\s*(.+?)\s*[((](.+?)[))]\s*$', node["标题"])
|
||||
if m:
|
||||
node["药名"], node["五行互含名位"] = m.group(1), m.group(2)
|
||||
else:
|
||||
node["药名"] = re.sub(r'^[一二三四五六七八九十]+、\s*', '', node["标题"])
|
||||
node["五行互含名位"] = None
|
||||
if chapters and chapters[-1].get("节"):
|
||||
chapters[-1]["节"][-1]["条目"].append(node)
|
||||
for c in chapters:
|
||||
for s in c["节"]:
|
||||
s["药物条目"] = [e for e in s["条目"] if e["类型"] == "条目"]
|
||||
s["附属标题"] = [e["标题"] for e in s["条目"] if e["类型"] == "附注"]
|
||||
return chapters
|
||||
|
||||
|
||||
def scan_missing_assets(text: str):
|
||||
"""登记悬空图片引用(OCR 流水线遗留,图片本体未随源文件提供)。"""
|
||||
lines = text.split("\n")
|
||||
out = []
|
||||
for i, l in enumerate(lines, start=1):
|
||||
for m in re.finditer(r'!\[\]\(([^)\n]+)\)', l):
|
||||
out.append({"行": i, "文件名": os.path.basename(m.group(1)), "原始引用": m.group(0)[:80],
|
||||
"上文": lines[i-3][:60] if i >= 3 else ""})
|
||||
return out
|
||||
|
||||
|
||||
def main():
|
||||
raw = open(SRC, encoding="utf-8").read()
|
||||
text, events, removed = clean_text(raw)
|
||||
chapters = parse_structure(text)
|
||||
missing_assets = scan_missing_assets(text)
|
||||
|
||||
def wf(path, content):
|
||||
os.makedirs(os.path.dirname(path), exist_ok=True)
|
||||
with open(path, "w", encoding="utf-8") as f:
|
||||
f.write(content); f.flush(); os.fsync(f.fileno())
|
||||
|
||||
wf(OUT_MD, text)
|
||||
struct = {
|
||||
"来源文件": os.path.basename(SRC), "来源文件md5": hashlib.md5(raw.encode()).hexdigest(),
|
||||
"清洗版文件": os.path.basename(OUT_MD), "清洗版md5": hashlib.md5(text.encode()).hexdigest(),
|
||||
"原始字符数": len(raw), "清洗后字符数": len(text),
|
||||
"说明": "行号均指清洗版;本文件仅作清理配套定位索引,未做释义抽取与跨库关联",
|
||||
"章": chapters,
|
||||
}
|
||||
wf(OUT_STRUCT, json.dumps(struct, ensure_ascii=False, indent=2) + "\n")
|
||||
|
||||
ch = chapters[0]
|
||||
secs = ch["节"]
|
||||
n_drug = sum(len(s["药物条目"]) for s in secs)
|
||||
cnt = lambda t: sum(1 for e in events if e["类型"] == t)
|
||||
|
||||
# 每节归属
|
||||
def owner(line):
|
||||
for s in secs:
|
||||
if s["起始行"] <= line <= s["结束行"]:
|
||||
return s
|
||||
return None
|
||||
per_sec = {s["标题"]: [] for s in secs}
|
||||
for e in events:
|
||||
o = owner(e["行"])
|
||||
if o is not None:
|
||||
per_sec[o["标题"]].append(e)
|
||||
|
||||
def ev_table(evs):
|
||||
rows = ["| 行 | 类型 | 原文 | 处理后 | 依据 |", "|----|------|------|--------|------|"]
|
||||
for e in evs:
|
||||
rows.append(f"| {e['行']} | {e['类型']} | {e['原'].replace('|','|')} | "
|
||||
f"{e['改'].replace('|','|')} | {e['依据']} |")
|
||||
return rows
|
||||
|
||||
rep = ["# 《辅行诀五脏用药法要》药性探真 第一章 — 文本清洗报告", "",
|
||||
"> 本库现阶段只做数据清理。用户 2026-09-15 指令:以第一章为源,待全文内容完整后再做加工/跨库关联/分析。", "",
|
||||
"## 0 概览", "",
|
||||
f"- 来源:`01_来源数据/{os.path.basename(SRC)}`(md5 `{struct['来源文件md5']}`)",
|
||||
f"- 清洗版:`02_加工数据/{os.path.basename(OUT_MD)}`(md5 `{struct['清洗版md5']}`)",
|
||||
f"- 字符数:{len(raw)} → {len(text)};行数:{raw.count(chr(10))} → {text.count(chr(10))}",
|
||||
f"- 结构:{ch['标题']} ── {len(secs)} 节 / 药物条目 {n_drug} 味", "",
|
||||
"| 清理类别 | 处数 | 说明 |", "|---------|------|------|",
|
||||
f"| A 页面残留物 | {removed['页眉'] + removed['页码']} | 页眉 {removed['页眉']} 行、独立页码 {removed['页码']} 行;另有行尾/全角/词间空格全量清理 |",
|
||||
f"| B 断行错位接合 | {cnt('B断行接合')} | 段落被页眉打断处复原成整段 |",
|
||||
f"| C 形近错字/异体字 | {cnt('C形近错字')} | 每条附核校依据,见下逐节明细 |",
|
||||
f"| E 半角标点规范化 | {cnt('E标点规范化')} | ASCII , ; : ( ) 邻接汉字时改全角 |",
|
||||
f"| F 存疑(未改原文) | {cnt('F存疑')} | 逐条列出疑正与核校来源,见 `人工核对清单.md` |", "",
|
||||
"### 各节清理量一览", "",
|
||||
"| 节 | 行范围 | 药物条目 | B 接合 | C 错字 | E 标点 | F 存疑 |",
|
||||
"|----|--------|---------|--------|--------|--------|--------|"]
|
||||
for s in secs:
|
||||
evs = per_sec[s["标题"]]
|
||||
c = lambda t: sum(1 for e in evs if e["类型"] == t)
|
||||
rep.append(f"| {s['标题']} | {s['起始行']}–{s['结束行']} | {len(s['药物条目'])} | "
|
||||
f"{c('B断行接合')} | {c('C形近错字')} | {c('E标点规范化')} | {c('F存疑')} |")
|
||||
|
||||
rep += ["", "---", "", "## 1 逐节核对明细(按章 / 节列明)", "",
|
||||
f"### {ch['标题']}(清洗版行 {ch['起始行']}–{ch['结束行']})", ""]
|
||||
for s in secs:
|
||||
evs = per_sec[s["标题"]]
|
||||
gate = f"味门{s['味门']}·{s['本脏']}{s['本行']}·法{s['脏象法象']}" if s.get("味门") else "从火土同治论心病(草木方例用药简释)"
|
||||
rep += [f"#### {s['标题']}", "",
|
||||
f"- 定位:清洗版行 {s['起始行']}–{s['结束行']};{gate};药物条目 {len(s['药物条目'])} 味",
|
||||
f"- 本味药:{'、'.join(e['药名'] for e in s['药物条目'])}",
|
||||
f"- 清理量:B 接合 {sum(1 for e in evs if e['类型']=='B断行接合')} / "
|
||||
f"C 错字 {sum(1 for e in evs if e['类型']=='C形近错字')} / "
|
||||
f"E 标点 {sum(1 for e in evs if e['类型']=='E标点规范化')} / "
|
||||
f"F 存疑 {sum(1 for e in evs if e['类型']=='F存疑')}", ""]
|
||||
if evs:
|
||||
rep += ev_table(evs) + [""]
|
||||
else:
|
||||
rep += ["- 本节无需修正条目。", ""]
|
||||
|
||||
rep += ["---", "", "## 2 章节结构(清洗版行号)", "",
|
||||
"| 章 | 节 | 味门 | 本脏/行/时 | 起始行 | 结束行 | 药物条目 | 附属标题 |",
|
||||
"|----|----|------|-----------|--------|--------|---------|---------|"]
|
||||
for s in secs:
|
||||
gate = f"{s.get('本脏','—')}/{s.get('本行','—')}/{s.get('脏象法象','—')}" if s.get("味门") else "—"
|
||||
rep.append(f"| {ch['标题']} | {s['标题']} | {s.get('味门') or '—'} | {gate} | {s['起始行']} | {s['结束行']} | "
|
||||
f"{len(s['药物条目'])} | {';'.join(s['附属标题']) or '—'} |")
|
||||
rep += ["", "## 3 缺失内容登记(来源不完整,非错字问题)", "",
|
||||
"| 项 | 情况 | 位置 | 处理 |", "|----|------|------|------|",
|
||||
f"| 悬空图片引用 | {len(missing_assets)} 处(OCR 流水线遗留,图片本体未随源文件提供) | "
|
||||
+ ";".join(f"行 {m['行']}({m['文件名'][:12]}…)" for m in missing_assets) + " | 原文保留引用,待补图 |",
|
||||
"| 脚注正文 | 正文存 ① ② 等标记 5 处(桂枝、人参、升麻、白醪法 2 处),脚注正文未随文录入 | 见上方逐节明细 F 类 | 待补后回填 |",
|
||||
"| 第二章及以后各章 | 本次来源仅第一章「五脏补泻草木方例 用药释义」 | — | 待补 |",
|
||||
"| 附录一至四 | 目录列有:整订稿/略论《汤液经法》与张仲景论著的关系/张大昌先生《处方正范》/张大昌先生《三十六脉名义略述》 | 来源文件首 3 行 | 待补 |", "",
|
||||
"## 4 药物条目清单(章节 → 药名 → 五行互含名位,原样保留)", "",
|
||||
"| 节 | 序 | 药名 | 五行互含名位 | 清洗版行范围 |", "|----|----|------|-------------|-------------|"]
|
||||
for s in secs:
|
||||
for k, e in enumerate(s["药物条目"], start=1):
|
||||
rep.append(f"| {s['标题']} | {k} | {e['药名']} | {e['五行互含名位'] or '—'} | {e['起始行']}–{e['结束行']} |")
|
||||
rep += ["", "> 说明:标题中的「五行互含名位」为原书表述(如「生姜木中火、干姜木中水」),清洗阶段原样保留,不作拆分或解释。"]
|
||||
wf(OUT_REPORT, "\n".join(rep) + "\n")
|
||||
|
||||
chk = ["# 人工核对清单 — 《辅行诀五脏用药法要》药性探真 第一章", "",
|
||||
"> 用途:需对照纸质原书/影印本确认的条目。核对清单**按章/节列明**,本阶段不改动清洗版正文。",
|
||||
"> 清洗流程与全部修正记录见 `文本清洗报告.md`。", "",
|
||||
f"## {ch['标题']}", ""]
|
||||
for s in secs:
|
||||
evs = [e for e in per_sec[s["标题"]] if e["类型"] == "F存疑"]
|
||||
chk += [f"### {s['标题']}(行 {s['起始行']}–{s['结束行']})", ""]
|
||||
if evs:
|
||||
chk += ["| 行 | 片段 | 疑正 / 核校来源 |", "|----|------|----------------|"]
|
||||
for e in evs:
|
||||
chk.append(f"| {e['行']} | {e['原'].replace('|','|')} | {e['依据']} |")
|
||||
else:
|
||||
chk.append("- 无存疑项。")
|
||||
chk.append("")
|
||||
chk += ["---", "", "## 缺失内容登记(本次来源不完整,非错字问题)", "",
|
||||
"| 项 | 情况 | 处理 |", "|----|------|------|",
|
||||
f"| 悬空图片引用 | {len(missing_assets)} 处:"
|
||||
+ ";".join(f"行 {m['行']} `{m['文件名']}`" for m in missing_assets)
|
||||
+ "(OCR 流水线遗留,图片本体未随源文件提供) | 待补图,补后替换为真实路径 |",
|
||||
"| 脚注正文 | 正文存 ① ② 等标记 5 处(桂枝、人参、升麻、白醪法 2 处),脚注正文未随文录入 | 待补后回填 |",
|
||||
"| 第二章及以后各章 | 本次来源仅第一章「五脏补泻草木方例 用药释义」 | 待补 |",
|
||||
"| 附录一至四 | 目录列有:整订稿/略论《汤液经法》与张仲景论著的关系/张大昌先生《处方正范》/张大昌先生《三十六脉名义略述》 | 待补 |",
|
||||
"| 表格 | 第一章正文不含表格 | — |",
|
||||
"| 图版 | 正文有 2 处图片引用,图片本体缺失(见上「悬空图片引用」) | 如有影印本可另补 |", "",
|
||||
"## 书目信息(供核对)", "",
|
||||
"- 书名:《辅行诀五脏用药法要》药性探真",
|
||||
"- 著者:衣之镖 撰著;丛书:张大昌先生弟子个人专著",
|
||||
"- 出版:学苑出版社,2014 年 1 月第 1 版,ISBN 978-7-5077-4414-9",
|
||||
"- 本次来源:`01_来源数据/药性探真_第一章_原始_20260915.md`(仅第一章)"]
|
||||
wf(OUT_CHECK, "\n".join(chk) + "\n")
|
||||
|
||||
print("清洗版:", OUT_MD, os.path.getsize(OUT_MD), "bytes")
|
||||
print("结构 :", OUT_STRUCT, os.path.getsize(OUT_STRUCT), "bytes")
|
||||
print("报告 :", OUT_REPORT, os.path.getsize(OUT_REPORT), "bytes")
|
||||
print("核对单:", OUT_CHECK, os.path.getsize(OUT_CHECK), "bytes")
|
||||
print(f"页眉/页码删除 {removed} | B接合 {cnt('B断行接合')} | C错字 {cnt('C形近错字')} | "
|
||||
f"E标点 {cnt('E标点规范化')} | F存疑 {cnt('F存疑')}")
|
||||
print(f"节 {len(secs)} 个 / 药物条目 {n_drug} 味")
|
||||
for s in secs:
|
||||
evs = per_sec[s["标题"]]
|
||||
print(f" {s['标题']} 行{s['起始行']}–{s['结束行']} 药物{len(s['药物条目'])} "
|
||||
f"| 清理项 {len(evs)} 条:" + "、".join(f"{e['类型'][:1]}@{e['行']}" for e in evs))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in new issue
Block a user