322 lines
22 KiB
Python
322 lines
22 KiB
Python
#!/usr/bin/env python3
|
||
# -*- coding: utf-8 -*-
|
||
"""
|
||
辅行诀五脏用药法要-药性探真 资料库 ETL 第 6 步(2026-09-17):本库内部**逐条对应**
|
||
输入:02_加工数据/整订稿_清洗版.md(衣之镖《整订稿》篇目/方目提纲,101 方目)
|
||
02_加工数据/辅行诀五脏用药法要_基础文本_清洗版.md(★底本,印刷本)
|
||
02_加工数据/印刷本结构_上下卷.json(底本篇/方索引,用作篇界与方目锚)
|
||
输出:03_关联融合/整订稿-底本_方目对照表.md
|
||
03_关联融合/整订稿-底本_方目对照.json
|
||
|
||
关联主轴(用户 2026-09-17「核对关联」指令):
|
||
主=底本(印刷本清洗版,用户 2026-09-16 定为基础文本);从=整订稿篇目提纲。
|
||
粒度=方目条 + 药行(草木药行/金石药行)行号锚定;**不改动任何一方原文**。
|
||
对位规则:
|
||
① 整订稿「X汤」 ↔ 底本「X汤散」条之**草木药行**(心篇四首无金石对应,底本即作「X汤」)
|
||
② 整订稿「X散汤」↔ 底本「X汤散」条之**金石药行**
|
||
③ 整订稿「大X汤/大X散汤」(救诸劳损病方篇)↔ 底本无独立方条,系依底本「若欲作大汤散者……」
|
||
加法(底本第 409 行)推得,关联至加法条 + 对应小方
|
||
④ 论说条(论证N条/论N条):与底本篇内方条之前的论说段落逐条核数
|
||
幂等:可重复运行;若底本或整订稿被重跑更新,本脚本按 md5 记录来源版本。
|
||
"""
|
||
import os, re, json, hashlib
|
||
|
||
BASE = os.path.expanduser("~/Documents/ai_agent_scraper_study/data/辅行诀五脏用药法要-药性探真")
|
||
F_ZD = os.path.join(BASE, "02_加工数据/整订稿_清洗版.md")
|
||
F_BASE = os.path.join(BASE, "02_加工数据/辅行诀五脏用药法要_基础文本_清洗版.md")
|
||
F_JSON = os.path.join(BASE, "02_加工数据/印刷本结构_上下卷.json")
|
||
OUT_MD = os.path.join(BASE, "03_关联融合/整订稿-底本_方目对照表.md")
|
||
OUT_JS = os.path.join(BASE, "03_关联融合/整订稿-底本_方目对照.json")
|
||
|
||
# ── 篇对位表:整订稿篇(清洗版字面)→ 底本篇(结构 JSON 标签)+篇题对位说明 ──
|
||
SEC_MAP = {
|
||
"辨肝脏病证文并方(论证四条,方八首)": ("上卷·辨肝脏病证文并方", "篇题同名(底本有篇题)", "方"),
|
||
"辨心脏病证文并方(论证五条,方四首)": ("上卷·辨心脏病证文并方", "篇题同名(底本有篇题)", "方"),
|
||
"又心包病方(论证一条,方八首)": ("上卷·辨心胞病证文(篇题缺)", "底本篇题缺;本提纲作「又心包病方」(字面),可补底本编次", "方"),
|
||
"辨脾脏病证文并方(论证四条,方八首)": ("上卷·辨脾脏病证文并方", "篇题同名(底本有篇题)", "方"),
|
||
"辨肺脏病证文并方(论证四条,方八首)": ("上卷·辨肺脏病证文并方", "篇题同名(底本有篇题)", "方"),
|
||
"辨肾脏病证文并方(论证四条,方八首)": ("上卷·辨肾脏病证文并方", "篇题同名(底本有篇题)", "方"),
|
||
"救诸病误治方(论证一首,方二十首)": ("上卷·救误泻五脏方(篇题缺)", "底本篇题缺;本提纲作「救诸病误治方」,底本引文作「又有泻方五首,以救诸病误治」", "方"),
|
||
"救诸劳损病方(论证二首,方二十首)": ("下卷·救五脏诸劳损病方(小方五首)", "底本引文作「经方有救诸劳损病方」;本提纲作「救诸劳损病方」", "方"),
|
||
"检录伊尹《汤液经法》方(六十一首)": ("下卷·汤液经法(二十五味药精)", "篇级对位(底本只存「今检录常情需用者六十一首」之数,无逐方目,与本提纲同)", "叙"),
|
||
"诸药五味五行互含文": ("下卷·汤液经法(二十五味药精条文)", "底本作「今者约列二十五种,以明五行互含之迹」(二十五味药精)", "叙"),
|
||
"心病诸药五行互含文": ("下卷·汤液经法(十三种药)", "底本作「又有药十三种,宜明其五行互含之事,以备心病方之用」", "叙"),
|
||
"五味补泻体用图": ("下卷·汤液经法(图注)", "底本图版缺失,仅存图注「此图乃《汤液经法》尽要之妙」", "叙"),
|
||
"外感天行病方(论二条,方十二首)": ("下卷·二旦四神大小汤(篇题缺)", "底本篇题缺;本提纲作「外感天行病方」", "方"),
|
||
"治中恶卒死方(论一条,方五首)": ("下卷·救五脏中恶卒死方(篇题缺)", "底本篇题缺;本提纲作「治中恶卒死方」", "方"),
|
||
"附:拟补心兼属土火金石补泻方四首": ("附录一·拟补心兼属土火金石补泻方四首", "篇题同名(底本作「附:拟补心兼属土火金石补泻方四首」)", "叙"),
|
||
"附:从火论心草木金石小补泻汤散四首": ("附录二·从火论心草木金石小补泻汤散四首", "篇题同名(底本作「附:从火论心草木金石小补泻汤散四首」)", "叙"),
|
||
}
|
||
# 篇题对位类型(用于差异分类)
|
||
HEAD_MAP_NOTE = {k: v[1] for k, v in SEC_MAP.items()}
|
||
|
||
CN = {"一":1,"二":2,"三":3,"四":4,"五":5,"六":6,"七":7,"八":8,"九":9,"十":10,
|
||
"十一":11,"十二":12,"十三":13,"十五":15,"二十":20}
|
||
DOSE = re.compile(r"(?:各|)[一二三四五六七八九十百]+(?:两|升|合|枚|斤|握|茎|锭|大枚|钱匕)")
|
||
# 底本「通论/结语/引文」类行首标记:方条正文范围到此为止(不含药材目录行)
|
||
EXCL_PREFIX = ("此篇所列", "陶云", "治疗劳损之方", "若欲作", "又有泻方",
|
||
"弘景曰", "陶隐居", "右五方", "若六畜", "上四十字")
|
||
FANG_RE = re.compile(r"^(?:救误|养生|调中|建中|凝息|固元)?(?:小|大)?[\u4e00-\u9fff()、]{2,12}?(?:汤散?|散|方)[::]")
|
||
OPEN_RE = re.compile(r"^(?:点眼|着舌|启咽|吹鼻|灌耳|熨耳)[\u4e00-\u9fff]{1,6}[::]")
|
||
|
||
|
||
def read(p):
|
||
raw = open(p, "rb").read()
|
||
return raw.decode("utf-8"), hashlib.md5(raw).hexdigest()
|
||
|
||
|
||
def lines_of(text):
|
||
return text.split("\n")
|
||
|
||
|
||
def load_bendi():
|
||
"""底本:篇界(结构 JSON)+ 方目(同名正则重算,含药行锚)"""
|
||
text, md5 = read(F_BASE)
|
||
js = json.load(open(F_JSON, encoding="utf-8"))
|
||
ls = lines_of(text)
|
||
secs = [dict(篇=n["篇"], 起始行=n["起始行"], 结束行=n["结束行"]) for n in js["篇"]]
|
||
excl = EXCL_PREFIX + tuple(a for v in ARGUE.values() for _ln, a in v)
|
||
starts = [f["起始行"] for f in js["方"]]
|
||
fangs = []
|
||
for idx, f in enumerate(js["方"]):
|
||
a = f["起始行"]
|
||
nxt = starts[idx + 1] if idx + 1 < len(starts) else len(ls) + 1
|
||
body = []
|
||
for i in range(a, nxt):
|
||
s = ls[i - 1].strip()
|
||
if i > a and (s.startswith("#") or any(s.startswith(x) for x in excl)):
|
||
break
|
||
if s:
|
||
body.append(i)
|
||
end = body[-1] if body else a
|
||
if end < a:
|
||
raise SystemExit(f"方条范围异常:{f['方名']}")
|
||
drug = [i for i in body if DOSE.search(ls[i - 1]) and not ls[i - 1].strip().startswith("右")]
|
||
fangs.append(dict(篇=f["篇"], 方名=f["方名"], 起始行=a, 结束行=end,
|
||
草木药行=drug[0] if drug else None,
|
||
金石药行=drug[-1] if len(drug) >= 2 else None))
|
||
return text, md5, js, secs, fangs
|
||
|
||
|
||
def load_zhengding():
|
||
text, md5 = read(F_ZD)
|
||
js = json.load(open(os.path.join(BASE, "02_加工数据/整订稿结构_篇方.json"), encoding="utf-8"))
|
||
return text, md5, js["方"], js["篇"]
|
||
|
||
|
||
def norm_base_name(name):
|
||
"""整订稿条目名 -> 底本方名候选(去「散汤」/「汤」后缀、心包->心胞、去附注)"""
|
||
n = re.sub(r"(附[^)]*)", "", name)
|
||
n = n.replace("(心包)", "(心胞)")
|
||
return n, re.sub(r"(散汤|汤)$", "", n)
|
||
|
||
|
||
# 论说条核对:底本各篇「论证段」行号(人工核定 + 首字锚校验;不含篇题/方条/通论结语)
|
||
ARGUE = {
|
||
"上卷·辨肝脏病证文并方": [(9, "肝虚则恐"), (11, "肝病者"), (13, "邪在肝"), (15, "陶云:肝德在散")],
|
||
"上卷·辨心脏病证文并方": [(55, "心虚则悲不已"), (57, "心病者"), (59, "邪在心"), (61, "经云:诸邪在心"), (63, "陶云:心德在耎")],
|
||
"上卷·辨心胞病证文(篇题缺)": [(89, "心胞气实者")],
|
||
"上卷·辨脾脏病证文并方": [(129, "脾实则"), (131, "脾病者"), (133, "邪在脾"), (135, "陶云:脾德在缓")],
|
||
"上卷·辨肺脏病证文并方": [(175, "肺虚则鼻息不利"), (177, "肺病者"), (179, "邪在肺"), (181, "陶云:肺德在收")],
|
||
"上卷·辨肾脏病证文并方": [(221, "肾气虚则厥逆"), (223, "肾病者"), (225, "邪在肾"), (227, "陶云:肾德在坚")],
|
||
"上卷·救误泻五脏方(篇题缺)": [(267, "又有泻方五首")],
|
||
"下卷·救五脏诸劳损病方(小方五首)": [(361, "陶云:经方有救诸劳损病方"), (363, "治疗劳损之方")],
|
||
"下卷·二旦四神大小汤(篇题缺)": [(437, "弘景曰:外感天行"), (511, "弘景曰:阳旦者")],
|
||
"下卷·救五脏中恶卒死方(篇题缺)": [(513, "陶隐居云:中恶卒死者")],
|
||
}
|
||
|
||
|
||
def main():
|
||
btext, bmd5, bjs, secs, bfangs = load_bendi()
|
||
ztext, zmd5, zfangs, zheads = load_zhengding()
|
||
bls = lines_of(btext)
|
||
|
||
by_sec_name = {}
|
||
for f in bfangs:
|
||
by_sec_name.setdefault(f["篇"], {})[f["方名"]] = f
|
||
|
||
rows, diffs, miss = [], [], []
|
||
for z in zfangs:
|
||
sec = z["篇"]
|
||
bsec, head_note, kind = SEC_MAP[sec]
|
||
zname = z["方名"]
|
||
jixing = "散汤(金石)" if zname.endswith("散汤") else "汤(草木)"
|
||
base, stem = norm_base_name(zname)
|
||
cands = ["%s汤散" % stem, "%s汤" % stem, stem]
|
||
hit = next((by_sec_name.get(bsec, {}).get(c) for c in cands
|
||
if by_sec_name.get(bsec, {}).get(c)), None)
|
||
note = ""
|
||
if hit is None and stem.startswith("大") and sec.startswith("救诸劳损"):
|
||
small = "小" + stem[1:]
|
||
s2 = by_sec_name.get(bsec, {}).get(small + "汤散") or by_sec_name.get(bsec, {}).get(small + "汤")
|
||
hit = dict(篇=bsec, 方名="(底本无独立方条)", 起始行=409, 结束行=409,
|
||
草木药行=None, 金石药行=None) if s2 else None
|
||
note = (f"底本只列小方五首({small}汤散 行 {s2['起始行']}–{s2['结束行']}),"
|
||
f"大方依底本行 409「若欲作大汤散者,补肝汤内加鸡肝……」加法推得,无独立条文"
|
||
if s2 else "未找到小方")
|
||
hit = dict(hit, 关联小方=f"{small}汤散(行 {s2['起始行']}–{s2['结束行']})" if s2 else "")
|
||
if hit is None:
|
||
miss.append((z["编号"], zname, sec))
|
||
rows.append(dict(编号=z["编号"], 整订稿方名=zname, 篇=sec, 剂型=jixing,
|
||
底本方名="—", 底本行="—", 说明="**未落位**"))
|
||
diffs.append(f"编号 {z['编号']}「{zname}」未能在底本落位")
|
||
continue
|
||
if jixing.startswith("散汤"):
|
||
anchor = hit.get("金石药行")
|
||
anchor_txt = f"金石药行 {anchor}" if anchor else "金石药行(未检出)"
|
||
else:
|
||
anchor = hit.get("草木药行")
|
||
anchor_txt = f"草木药行 {anchor}" if anchor else "草木药行(未检出)"
|
||
# 差异分类
|
||
cls = []
|
||
if hit["方名"].endswith("汤散") and zname.endswith("散汤"):
|
||
cls.append("体例:底本「X汤散」条之金石散方 = 整订稿「X散汤」")
|
||
elif hit["方名"].endswith("汤散") and not zname.endswith("散汤"):
|
||
cls.append("体例:底本「X汤散」条之草木方 = 整订稿「X汤」")
|
||
if "(心包)" in zname or "心包" in zname:
|
||
cls.append("用字:整订稿「心包」/底本「心胞」(不校,只登记)")
|
||
if stem.startswith("大") and sec.startswith("救诸劳损"):
|
||
cls.append("底本无独立方条(依大汤加法推得)")
|
||
if re.search(r"(附[^)]*)", zname):
|
||
cls.append("篇内附方(底本另出条文,非编号方)")
|
||
m = re.search(r"(附([^)]*))", zname)
|
||
fu = by_sec_name.get(bsec, {}).get(m.group(1))
|
||
if fu:
|
||
note = (note + f";底本另出附方「{m.group(1)}」(行 {fu['起始行']}–{fu['结束行']},"
|
||
f"底本结语作「右五方」故不计入编号)").strip(";")
|
||
if anchor is None and sec.startswith("治中恶"):
|
||
note = (note + ";本篇为外用/吐法方,底本无常规药味行").strip(";")
|
||
rows.append(dict(编号=z["编号"], 整订稿方名=zname, 篇=sec, 剂型=jixing,
|
||
底本篇=bsec, 底本方名=hit["方名"],
|
||
底本行=f"{hit['起始行']}–{hit['结束行']}",
|
||
锚=anchor_txt, 差异=cls, 说明=note))
|
||
|
||
# 论说条核对:底本各篇「论证段」条数 vs 整订稿篇题标称(锚校验)
|
||
def argue_count(sec_label):
|
||
ref = ARGUE.get(sec_label, [])
|
||
n = 0
|
||
for ln, anchor in ref:
|
||
if not bls[ln - 1].strip().startswith(anchor):
|
||
raise SystemExit(f"论证段锚校验失败:底本行 {ln} 应以「{anchor}」起,实为「{bls[ln-1][:24]}」")
|
||
n += 1
|
||
return n, [ln for ln, _ in ref]
|
||
|
||
def declared(t, kw):
|
||
m = re.search(kw + r"([一二三四五六七八九十]+)(?:条|首)", t)
|
||
return CN.get(m.group(1)) if m else None
|
||
|
||
arg_rows = []
|
||
for h in zheads:
|
||
sec = h["篇"]
|
||
bsec, head_note, kind = SEC_MAP[sec]
|
||
if kind == "叙":
|
||
arg_rows.append(dict(整订稿篇=sec, 底本篇=bsec, 整订稿标称="(无)",
|
||
底本实测="—", 判定="篇级对位(无方目)", 篇题对位=head_note))
|
||
continue
|
||
dec_a = declared(sec, "论证") or declared(sec, "论")
|
||
act_a, arg_lines = argue_count(bsec)
|
||
dec_f = h.get("篇题标称方数")
|
||
nb = len([f for f in bfangs if f["篇"] == bsec])
|
||
nz = h["方数"]
|
||
nb_note = f"{nb} 首"
|
||
if sec.startswith("治中恶"):
|
||
nb_note = "5 首 + 篇内附 2 首(启咽方、熨耳以通心气,不编号)"
|
||
nb = 5
|
||
if sec.startswith("辨心"):
|
||
ratio = "本篇底本无同构金石方,故汤/散不分立"
|
||
elif sec.startswith("救诸劳损"):
|
||
ratio = "小方 5 × 2(汤/散分立)+ 大方 5 × 2(依底本大汤加法推得,底本无独立方条)"
|
||
elif nb and nz == nb * 2:
|
||
ratio = "整订稿「汤/散」分立计"
|
||
else:
|
||
ratio = "本篇无汤/散分立(一草一汤)"
|
||
ok_a = "✅ 相符" if dec_a == act_a else f"⚠ 不符(标称 {dec_a} / 实测 {act_a})"
|
||
ok_f = "✅ 相符" if dec_f == nz else f"⚠ 不符(标称 {dec_f} / 实列 {nz})"
|
||
arg_rows.append(dict(整订稿篇=sec, 底本篇=bsec,
|
||
整订稿标称=f"论证 {dec_a} 条 · 方 {dec_f} 首",
|
||
底本实测=f"论证 {act_a} 段(行 {'、'.join(map(str, arg_lines))})· 方条 {nb_note}",
|
||
判定=f"论证 {ok_a};方数 {ok_f}({nz} = 底本 {nb} × {nz // nb if nb else '—'};{ratio})",
|
||
篇题对位=head_note))
|
||
|
||
# 落位自检
|
||
n_ok = sum(1 for r in rows if r["底本方名"] != "—")
|
||
checks = [f"方目落位 {n_ok}/{len(zfangs)}"
|
||
+ ("(全部落位)" if n_ok == len(zfangs) else "**有未落位项**")]
|
||
checks.append("论说条 / 方数 逐篇核对:" +
|
||
("全部相符" if all("⚠" not in r["判定"] for r in arg_rows) else "**有不符项**"))
|
||
checks.append(f"底本方目总数 {len(bfangs)}(结构 JSON)→ 整订稿方目 {len(zfangs)}(汤/散分立计)")
|
||
|
||
js = dict(
|
||
底本=dict(文件=os.path.basename(F_BASE), md5=bmd5),
|
||
整订稿=dict(文件=os.path.basename(F_ZD), md5=zmd5),
|
||
关联主轴="主=底本(印刷本清洗版);从=整订稿篇目提纲;粒度=方目条 + 药行行号;不改动原文",
|
||
自检=checks, 篇级核对=arg_rows,
|
||
方目对照=[dict(编号=r["编号"], 整订稿方名=r["整订稿方名"], 篇=r["篇"], 剂型=r["剂型"],
|
||
底本篇=r.get("底本篇"), 底本方名=r["底本方名"], 底本行=r["底本行"],
|
||
锚=r["锚"], 差异=r["差异"], 说明=r["说明"]) for r in rows],
|
||
未落位=miss)
|
||
os.makedirs(os.path.dirname(OUT_JS), exist_ok=True)
|
||
with open(OUT_JS, "w", encoding="utf-8") as f:
|
||
f.write(json.dumps(js, ensure_ascii=False, indent=2) + "\n")
|
||
|
||
md = ["# 整订稿 ⇄ 底本 方目对照表(本库内部逐条对应)", "",
|
||
"> **关联主轴**:主=**底本**(`02_加工数据/辅行诀五脏用药法要_基础文本_清洗版.md`,"
|
||
"印刷本,用户 2026-09-16 定为基础文本);从=**整订稿篇目提纲**"
|
||
"(`02_加工数据/整订稿_清洗版.md`,衣之镖《整订稿》篇目/方目,编号 1–101)。",
|
||
"> **粒度**:方目条 + 药行(草木药行/金石药行)行号锚定,行号一律指各自清洗版;**不改动任何一方原文**。",
|
||
f"> 版本:底本 md5 `{bmd5}`;整订稿 md5 `{zmd5}`;脚本 `05_脚本工具/06_link_zhengding.py`(幂等可重跑)", "",
|
||
"## 一、对位规则", "",
|
||
"| 整订稿条目 | 底本对位 | 落地锚 |", "|-----------|---------|--------|",
|
||
"| X汤 | 底本「X**汤散**」条(草木方+金石散同条)之**草木药行** | 方条行范围 + 草木药行行号 |",
|
||
"| X散汤 | 同上条之**金石药行**(同构金石方) | 同条行范围 + 金石药行行号 |",
|
||
"| 大X汤/大X散汤(救诸劳损病方篇) | 底本**无独立方条**;依底本行 409「若欲作大汤散者……」加法推得 | 加法行 409 + 对应小方行范围 |",
|
||
"| 篇内附(启咽方、熨耳以通心气) | 底本另出条文(非编号方) | 底本对应行 |",
|
||
"| 检录伊尹《汤液经法》方(六十一首)/诸药五味五行互含文/心病诸药五行互含文/五味补泻体用图 | 篇级对位(无逐方目) | 底本篇行范围 |",
|
||
"", "## 二、篇级核对(论证条数 · 方数 · 篇题)", "",
|
||
"| 整订稿篇 | 底本篇(本库标签) | 整订稿标称 | 底本实测 | 判定 |", "|---------|------------------|-----------|---------|------|"]
|
||
for r in arg_rows:
|
||
md.append(f"| {r['整订稿篇']} | {r['底本篇']} | {r['整订稿标称']} | {r['底本实测']} | {r['判定']} |")
|
||
|
||
md += ["", "## 三、方目逐条对照(整订稿 1–101 → 底本行号)", "",
|
||
"> 行号一律指各自**清洗版**;「落地锚」给出该条在底本中的药行行号(散汤=金石药行,余=草木药行)。",
|
||
"> 差异登记栏只列**体例/用字**之异,非校勘结论;底本为准,不作改写。", "",
|
||
"| 编号 | 整订稿方名 | 篇 | 剂型 | 底本方名 | 底本行 | 落地锚 | 差异登记 | 备注 |",
|
||
"|------|-----------|----|------|---------|--------|--------|---------|------|"]
|
||
for r in rows:
|
||
md.append(f"| {r['编号']} | {r['整订稿方名']} | {r['篇'].split('(')[0]} | {r['剂型']} | "
|
||
f"{r['底本方名']} | {r['底本行']} | {r['锚']} | {';'.join(r['差异']) or '—'} | "
|
||
f"{r['说明'] or '—'} |")
|
||
md += ["", "## 四、附录二种与篇内附方(整订稿不编号者)", "",
|
||
"| 整订稿篇/附 | 底本对位 | 底本行 |", "|-------------|---------|--------|",
|
||
"| 附:拟补心兼属土火金石补泻方四首 | 小泻心散/大泻心散/小补心散/大补心散(4 首,底本不另编号) | "
|
||
+ "、".join(str(f["起始行"]) for f in bfangs if f["篇"].startswith("附录一")) + " |",
|
||
"| 附:从火论心草木金石小补泻汤散四首 | 小泻心汤散/小补心汤散(题称四首 = 草木方+金石方各一) | "
|
||
+ "、".join(str(f["起始行"]) for f in bfangs if f["篇"].startswith("附录二")) + " |",
|
||
"| 99.启咽以通脾气(附启咽方) | 启咽以通脾气(行 523)+启咽方(行 527,附) | 523/527 |",
|
||
"| 101.灌耳以通肾气(附熨耳以通心气) | 灌耳以通肾气(行 535)+熨耳以通心气(行 539,附) | 535/539 |",
|
||
"", "## 五、自检", ""]
|
||
for c in checks:
|
||
md.append(f"- {'✅' if '**' not in c else '⚠'} {c}")
|
||
if miss:
|
||
md += ["", "**未落位项**:"] + [f"- 编号 {a}「{b}」({c})" for a, b, c in miss]
|
||
md += ["", "---", "",
|
||
"> 📅 2026-09-17 —— 建立本库内部逐条对应(用户「核对关联」指令);"
|
||
f"底本方目 {len(bfangs)} 首 ⇄ 整订稿方目 {len(zfangs)} 条(汤/散分立);"
|
||
f"落位 {n_ok}/{len(zfangs)}。差异清单与结论见 `整订稿核对报告.md`。"]
|
||
with open(OUT_MD, "w", encoding="utf-8") as f:
|
||
f.write("\n".join(md) + "\n")
|
||
|
||
print("对照表:", OUT_MD, os.path.getsize(OUT_MD), "bytes")
|
||
print("对照 :", OUT_JS, os.path.getsize(OUT_JS), "bytes")
|
||
for c in checks:
|
||
print(" ", c)
|
||
if miss:
|
||
print(" 未落位:", miss)
|
||
print("--- 篇级核对 ---")
|
||
for r in arg_rows:
|
||
print(f" {r['整订稿篇'][:14]:<16} | {r['整订稿标称']:<22} | {r['底本实测']:<30} | {r['判定']}")
|
||
|
||
|
||
if __name__ == "__main__":
|
||
main()
|