初始归档:健康管理资料库(大医网/药膳/体质监测/中医理论等12个资料集,7712个文件)
This commit is contained in:
commit
80ae3811cf
7712 files changed
+4628547
No files matched your search
@@ -0,0 +1,669 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
辅行诀五脏用药法要-药性探真 资料库 ETL 第 15 步(2026-09-22):
|
||||
**《辅行诀五脏用药法要》(底本,主)⇄ 《药性探真》第 1–3 章合卷本(从)** 的初步数据关联。
|
||||
|
||||
用户指令(2026-09-22):「初步进行《辅行诀五脏用药法要》与《辅行诀五脏用药法要 药性探真》的
|
||||
数据关联,《辅行诀五脏用药法要》作为古本,是基础」。
|
||||
→ 主从:**主=底本**(`02_加工数据/辅行诀五脏用药法要_基础文本_清洗版.md`,印刷本,
|
||||
用户 2026-09-16 定为 baseline);**从=《药性探真》第 1–3 章合卷本**(研究文献,级别低于底本)。
|
||||
→ 粒度:**药物级(药名+五味五行互含名位)+ 方剂级(方名)+ 药—方—阐释 三级串联**。
|
||||
→ 铁律:**差异只登记、不改任何一方原文**;锚校验(唯一命中);md5 登记;幂等可重跑。
|
||||
|
||||
三层关联:
|
||||
① 药物级:探真条目(药名+「X中Y」名位)⇄ 底本《汤液经法》二十五味药精/十三种药(L415–423/L429)
|
||||
② 方剂级:底本 64 首方名 ⇄ 探真正文所引方名(反向索引:该方在探真哪一章哪条被引用)
|
||||
③ 药—方—阐释:底本每首方的药味行 → 各药在探真中的释义位置(行号锚)
|
||||
|
||||
产物(03_关联融合/):
|
||||
药性探真-底本_药名方目对照表.md 人读:对位规则/药物级对位/方剂级索引/方—药—阐释三级表/自检
|
||||
药性探真-底本_药名方目对照.json 机器读:md5、三层关联、差异分类、未落位项、自检
|
||||
药性探真-底本_核对报告.md 结论、差异 D1–Dn、用法、缺口与待决(带优先级)
|
||||
|
||||
用法:
|
||||
cd ~/Documents/ai_agent_scraper_study/data/辅行诀五脏用药法要-药性探真
|
||||
python3 05_脚本工具/15_link_tanzhen.py # 生成/刷新(幂等)
|
||||
python3 05_脚本工具/15_link_tanzhen.py --check # 只校验,不写盘
|
||||
"""
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import json
|
||||
import hashlib
|
||||
import collections
|
||||
|
||||
BASE = os.path.expanduser("~/Documents/ai_agent_scraper_study/data/辅行诀五脏用药法要-药性探真")
|
||||
|
||||
BENDI_MD = "02_加工数据/辅行诀五脏用药法要_基础文本_清洗版.md"
|
||||
BENDI_JSON = "02_加工数据/印刷本结构_上下卷.json"
|
||||
BENDI_MD5 = "84ea3f9273b7be1573f9261e94632224" # baseline 冻结值
|
||||
TZ_MD = "02_加工数据/药性探真_第1-3章_合并清洗版.md"
|
||||
TZ_JSON = "02_加工数据/药性探真_第1-3章_合并结构.json"
|
||||
TZ_MD5 = "85aaf1122134092ffa653a709e10fdd6"
|
||||
|
||||
OUT_TABLE = "03_关联融合/药性探真-底本_药名方目对照表.md"
|
||||
OUT_JSON = "03_关联融合/药性探真-底本_药名方目对照.json"
|
||||
OUT_REPORT = "03_关联融合/药性探真-底本_核对报告.md"
|
||||
|
||||
POS = r"[木火土金水]中[木火土金水]"
|
||||
YAO_ANCHORS = [(415, "味辛皆属木"), (417, "味咸皆属火"), (419, "味甘皆属土"),
|
||||
(421, "味酸皆属金"), (423, "味苦皆属水")]
|
||||
THIRTEEN_LINE = 429 # 「通草为木中土,又为木中水;…」
|
||||
|
||||
# ── 药名归一(显式表;只用于查表,不改原文)────────────────────────────────
|
||||
# 探真药名 → 底本药精/十三种药名;None = 底本无此品(作者拟补/底本另论)
|
||||
TZ2BASE = {
|
||||
# 第 1 章 草木(二十五味药精之草木)
|
||||
"桂枝": "桂", "生姜": "生姜", "干姜": "干姜", "附子": "附子", "细辛": "细辛",
|
||||
"牡丹皮": "丹皮", "大黄": "大黄", "葶苈子": "葶苈子", "泽泻": "泽泻", "旋覆花": "旋覆花",
|
||||
"人参": "人参", "生甘草": "甘草", "炙甘草": "甘草炙", "茯苓": "茯苓", "薯蓣": "薯蓣",
|
||||
"麦门冬": "麦门冬", "枳实": "枳实", "芍药": "芍药", "山茱萸": "萸肉", "五味子": "五味子",
|
||||
"地黄": "地黄", "黄芩": "黄芩", "黄连": "黄连", "术": "术", "竹叶": "竹叶",
|
||||
# 第 1 章 第六节(十三种药)
|
||||
"通草": "通草", "淡豆豉": "淡豆豉", "升麻": "升麻", "栀子": "栀子", "元参": None,
|
||||
"酢": "酢", "栝蒌": "栝楼", "牡桂": "牡桂", "薤白": "薤白", "白酨浆": "白酨浆", "半夏": "半夏",
|
||||
# 第 3 章 金石(二十五味药精之金石)
|
||||
"青琅玕": "琅玕", "伏龙肝": "伏龙肝", "阳起石": "阳起石", "礜石": "礜石", "雄黄": "雄黄",
|
||||
"凝水石": "凝水石", "禹余粮": "禹粮石", "硝石": "硝石", "火硝": "硝石", "芒硝": "芒硝",
|
||||
"朴硝": None, "卤碱": None, "磁石": "磁石", "赤石脂": "赤石脂", "石膏": "石膏",
|
||||
"石钟乳": "乳石", "云母": "云母", "石英": "石英", "绿青": "石绿", "石绿": "石绿",
|
||||
"曾青": "曾青", "石胆": None, "矾石": "白矾", "白矾": "白矾", "皂矾": "皂矾",
|
||||
"石硫磺": "硫黄", "滑石": "滑石", "代赭石": "代赭石", "丹砂": "丹砂", "黄土": "黄土",
|
||||
"白垩": "白垩土", "铁落": None, "石蜜": None, "理石": None, "姜石": None, "硇砂": None,
|
||||
"海蛤": None, "戎盐": "戎盐",
|
||||
}
|
||||
# 底本药味名 → 探真条目名(用于「药—方—阐释」串联);None = 探真未收(登记为缺口)
|
||||
BASE2TZ = {
|
||||
"桂": "桂枝", "生姜": "姜", "干姜": "姜", "附子": "附子", "细辛": "细辛", "丹皮": "牡丹皮",
|
||||
"大黄": "大黄", "葶苈子": "葶苈子", "泽泻": "泽泻", "旋覆花": "旋覆花", "人参": "人参",
|
||||
"甘草": "甘草", "甘草炙": "甘草", "茯苓": "茯苓", "薯蓣": "薯蓣", "麦门冬": "麦门冬",
|
||||
"枳实": "枳实", "芍药": "芍药", "萸肉": "山茱萸", "五味子": "五味子", "地黄": "地黄",
|
||||
"黄芩": "黄芩", "黄连": "黄连", "术": "术", "白术": "术", "竹叶": "竹叶",
|
||||
"通草": "通草", "淡豆豉": "淡豆豉", "升麻": "升麻", "栀子": "栀子", "酢": "酢",
|
||||
"栝楼": "栝蒌", "栝蒌": "栝蒌", "牡桂": "牡桂", "薤白": "薤白", "白酨浆": "白酨浆",
|
||||
"白酨": "白酨浆", "半夏": "半夏", "琅玕": "青琅玕", "伏龙肝": "伏龙肝",
|
||||
"阳起石": "阳起石", "礜石": "礜石", "雄黄": "雄黄", "凝水石": "凝水石",
|
||||
"禹粮石": "禹余粮", "硝石": "硝石", "芒硝": "硝石", "朴硝": "硝石", "卤硷": "硝石",
|
||||
"卤碱": "硝石", "磁石": "磁石", "赤石脂": "赤石脂", "石膏": "石膏", "乳石": "石钟乳",
|
||||
"云母": "云母", "石英": "石英", "石绿": "绿青", "曾青": "曾青", "石胆": "石胆",
|
||||
"白矾": "矾石", "皂矾": "矾石", "硫黄": "石硫磺", "滑石": "滑石", "代赭石": "代赭石",
|
||||
"丹砂": "丹砂", "黄土": "黄土", "白垩土": "白垩", "铁落": "铁落", "石蜜": "石蜜",
|
||||
"理石": "理石", "姜石": "姜石", "硇砂": "硇砂", "海蛤": "海蛤", "戎盐": "戎盐",
|
||||
"玄参": "元参", "生地黄": "地黄", "生地": "地黄", "桂心": "桂枝",
|
||||
# 第 2 章(菜果谷畜)与方中药味
|
||||
"韭": "肝菜韭", "葱叶": "肺菜葱", "葱": "肺菜葱", "葱白": "肺菜葱", "藿": "心菜藿",
|
||||
"桃奴": "桃奴", "桃核仁": "桃核仁", "栗": "肾水果栗", "栗仁": "肾水果栗",
|
||||
"大枣": "脾土果大枣", "李": "肝木果李", "苦杏": "杏核仁", "杏仁": "杏核仁", "杏核仁": "杏核仁",
|
||||
"饴": "脾土谷物黄饴", "黄饴": "脾土谷物黄饴", "苦酒": "肾水谷物苦酒",
|
||||
"鸡肝": "肺金畜鸡肝", "豕心": "肾水畜猪心", "牛脾": "脾土畜牛脾", "犬肺": "肝木畜犬肺",
|
||||
"羊肾": "心火畜羊肾", "麻黄": "麻黄", "黄耆": "黄芪", "阿胶": "阿胶", "知母": "知母",
|
||||
"赤小豆": "赤小豆", "瓜蒂": "瓜蒂", "皂荚": "皂荚", "牡蛎": "牡蛎", "橘皮": "橘皮",
|
||||
"厚朴": "厚朴", "桔梗": "桔梗", "射干": "射干", "梅实": "梅实", "猪苓": "猪苓",
|
||||
"竹茹": "竹茹", "款冬花": "款冬花", "茅根": "茅根",
|
||||
# 探真未收(方中药味;登记缺口,不臆配)
|
||||
"粳米": None, "鸡子黄": None, "柴胡": None, "咸豉": "淡豆豉", "豉": "淡豆豉",
|
||||
"滑": None, "熬": None, "绵裹": None, "捣如泥": None, "打": None,
|
||||
"共为极细": None, "入戎盐": "戎盐", "戎盐(玄参)": "戎盐",
|
||||
}
|
||||
|
||||
DOSE = re.compile(r"(?:各)?[一二三四五六七八九十百半]+(?:大枚|大握|大把|大升|钱匕|两|升|合|枚|斤|握|茎|锭|把|分|斗)")
|
||||
DOSE2 = re.compile(r"(?:如鸡子大|等分|少许|半)$")
|
||||
CURED = re.compile(r"(熬黑|熬|切|炮|洗|炙|研末|研|碎|擘|炒|烧存性|烧|末|杵|锉|去皮尖|去皮|"
|
||||
r"去核擘|去核|去心|去芦|去毛|焙|晒|干|汁|自然汁|浆|煮|微炒|酒洗|水洗|"
|
||||
r"去翅足|去足翅|捣碎|捣|去滑|烧赤|取冷|为细粉|去节)$")
|
||||
JIAJIAN = re.compile(r"(者,?(?:加|去|倍|仍)|,加|倍[\u4e00-\u9fa5]{1,4}为|去[\u4e00-\u9fa5]{1,4}加)")
|
||||
JIA = re.compile(r"([加倍])([\u4e00-\u9fa5]{1,4}?)(?=[一二三四五六七八九十百半]+"
|
||||
r"(?:两|升|合|枚|斤|钱匕|大枚)|,|;|。|$)")
|
||||
QU = re.compile(r"去([\u4e00-\u9fa5]{1,4}?)(?=加|,|;|。|$)")
|
||||
|
||||
# 用字/体例差异(人工核定后写入;只登记,不校改任何一方)——每条须可复核(行号 + 原句)
|
||||
WORD_NOTES = [
|
||||
("D5 用字不一(从本内部)", "探真 L1495「《辅行诀·建中补脾汤》」/L1599·L1603「大健中补脾汤」",
|
||||
"同一方名在探真内部**两形并用**(建/健);底本作「小建中补脾汤散」(另 L409「大汤加法」)"
|
||||
"——属研究文献行文用字,只登记、不校改;**检索须两形并用**"),
|
||||
("D5 用字不一(两侧)", "底本「丹皮」「萸肉」「禹粮石」「乳石」「白垩土」「硫黄」「琅玕」",
|
||||
"探真作「牡丹皮」「山茱萸」「禹余粮」「石钟乳」「白垩」「石硫磺」「青琅玕」——**药名简称/全称之别**,"
|
||||
"经显式归一表对位(TZ2BASE/BASE2TZ),两侧原文均不改;**检索须两形并用**"),
|
||||
]
|
||||
|
||||
# 判定覆盖(前轮已裁定者,与本库第 1/3 章检查报告口径一致)
|
||||
JUDGE_OVERRIDE = {
|
||||
("曾青", "火中木"): "✅ 相符(同位对应:十三种药「五味子为金中土,又为火中木」,作者以曾青与五味子同位列)",
|
||||
("石胆", "木中火"): "✅ 相符(同位对应:十三种药「淡豆豉为木中火,又为水中木」,石胆与淡豆豉同位)",
|
||||
("石胆", "水中木"): "✅ 相符(同位对应:十三种药「淡豆豉为木中火,又为水中木」)",
|
||||
("铁落", "木中土"): "✅ 相符(同位对应:十三种药「通草为木中土,又为木中水」,铁落与通草同位)",
|
||||
("铁落", "木中水"): "✅ 相符(同位对应:十三种药「通草为木中土,又为木中水」)",
|
||||
("石蜜", "土中金"): "✅ 相符(同位对应:十三种药「升麻为土中金,又为土中火」,石蜜与升麻同位)",
|
||||
("石蜜", "土中火"): "✅ 相符(同位对应:十三种药「升麻为土中金,又为土中火」)",
|
||||
("五味子", "金中火"): "⚠ 抵牾(第 1 章第四节题名作「金中土、金中火」,底本作「金中土/火中木」;"
|
||||
"第 1 章待核对清单 #8 判决「暂留待核」)",
|
||||
}
|
||||
|
||||
|
||||
def md5_of(p):
|
||||
return hashlib.md5(open(p, "rb").read()).hexdigest()
|
||||
|
||||
|
||||
def read(rel):
|
||||
with open(os.path.join(BASE, rel), "rb") as f:
|
||||
raw = f.read()
|
||||
return raw.decode("utf-8"), hashlib.md5(raw).hexdigest()
|
||||
|
||||
|
||||
def wf(rel, content):
|
||||
p = os.path.join(BASE, rel)
|
||||
os.makedirs(os.path.dirname(p), exist_ok=True)
|
||||
with open(p, "w", encoding="utf-8") as f:
|
||||
f.write(content)
|
||||
f.flush()
|
||||
os.fsync(f.fileno())
|
||||
|
||||
|
||||
# ── ① 底本《汤液经法》药精表(oracle)────────────────────────────────────
|
||||
def parse_oracle(lines):
|
||||
tbl = []
|
||||
for ln, anchor in YAO_ANCHORS:
|
||||
line = lines[ln - 1]
|
||||
if not line.startswith(anchor):
|
||||
raise SystemExit(f"药精表锚校验失败:第 {ln} 行应以「{anchor}」起,实为「{line[:16]}」")
|
||||
hang = line[4]
|
||||
for seg in re.split(r"[。;]", line[line.index(",") + 1:]):
|
||||
seg = seg.strip()
|
||||
if not seg:
|
||||
continue
|
||||
m = re.match(r"^(\S+)\s+(\S+?)(为之主|为[木火土金水])$", seg)
|
||||
if not m:
|
||||
raise SystemExit(f"药精表条目非预期格式(L{ln}):{seg}")
|
||||
herb, mineral, rel = m.group(1), m.group(2), m.group(3)
|
||||
tbl.append(dict(名位=hang + "中" + (hang if rel == "为之主" else rel[1]),
|
||||
草木药=herb, 金石药=mineral, 底本行=ln))
|
||||
thirteen = []
|
||||
line = lines[THIRTEEN_LINE - 1]
|
||||
if not line.startswith("通草为木中土"):
|
||||
raise SystemExit(f"十三种药锚校验失败:第 {THIRTEEN_LINE} 行应为十三种药条文")
|
||||
for seg in line.split(";"):
|
||||
seg = seg.strip().rstrip("。")
|
||||
if not seg:
|
||||
continue
|
||||
if ",又为" in seg:
|
||||
m = re.match(rf"^(\S+?)为({POS}),又为({POS})$", seg)
|
||||
thirteen.append(dict(药=m.group(1), 名位=[m.group(2), m.group(3)], 底本行=THIRTEEN_LINE))
|
||||
elif "," in seg:
|
||||
for sub in seg.split(","):
|
||||
m = re.match(rf"^(\S+?)为({POS})$", sub)
|
||||
thirteen.append(dict(药=m.group(1), 名位=[m.group(2)], 底本行=THIRTEEN_LINE))
|
||||
else:
|
||||
m = re.match(rf"^(\S+?)为({POS})$", seg)
|
||||
thirteen.append(dict(药=m.group(1), 名位=[m.group(2)], 底本行=THIRTEEN_LINE))
|
||||
return tbl, thirteen
|
||||
|
||||
|
||||
# ── ② 探真条目 → 药物级行 ───────────────────────────────────────────────
|
||||
def split_top(s):
|
||||
out, depth, cur = [], 0, ""
|
||||
for ch in s:
|
||||
if ch in "((":
|
||||
depth += 1
|
||||
elif ch in "))":
|
||||
depth -= 1
|
||||
if ch == "、" and depth == 0:
|
||||
out.append(cur)
|
||||
cur = ""
|
||||
continue
|
||||
cur += ch
|
||||
if cur:
|
||||
out.append(cur)
|
||||
return out
|
||||
|
||||
|
||||
def parse_inner(inner):
|
||||
"""括注内容 → [(药名或None, 名位)]"""
|
||||
out = []
|
||||
for p in re.split(r"[、,]", inner):
|
||||
p = p.strip().lstrip("又为").strip()
|
||||
if not p:
|
||||
continue
|
||||
if re.fullmatch(POS, p):
|
||||
out.append((None, p))
|
||||
continue
|
||||
m = re.match(rf"^(.*?)({POS})$", p)
|
||||
out.append((m.group(1).strip() or None, m.group(2)) if m else (p, None))
|
||||
return out
|
||||
|
||||
|
||||
def parse_entry(title):
|
||||
"""条目题名 → [(药名, 名位列表)]"""
|
||||
t = re.sub(r"^[一二三四五六七八九十]+、", "", title).strip()
|
||||
if "(" not in t:
|
||||
return [(x.strip(), []) for x in split_top(re.sub(r"([^)]*)", "", t)) if x.strip()]
|
||||
res = []
|
||||
for part in split_top(t):
|
||||
m = re.match(r"^([^(]+)((.*))$", part.strip())
|
||||
if not m:
|
||||
res.append((part.strip(), []))
|
||||
continue
|
||||
head, inner = m.group(1).strip(), m.group(2)
|
||||
if inner.startswith("即"):
|
||||
seg = re.split(r"[,,]", inner[1:], maxsplit=1)
|
||||
inner = seg[1] if len(seg) > 1 else ""
|
||||
items = parse_inner(inner)
|
||||
# 单药多名的情形(如「姜(生姜木中火、干姜木中水)」)→ 各药单列
|
||||
if items and all(nm for nm, _ in items):
|
||||
for nm, p in items:
|
||||
res.append((nm, [p] if p else []))
|
||||
else:
|
||||
poss = [p for _, p in items if p]
|
||||
res.append((head, poss))
|
||||
return res
|
||||
|
||||
|
||||
def build_drug_rows(tz_struct):
|
||||
rows = []
|
||||
for ch in tz_struct["章"]:
|
||||
for sec in ch["节"]:
|
||||
for e in sec["条目"]:
|
||||
for name, poss in parse_entry(e["条目"]):
|
||||
rows.append(dict(章=ch["章"], 节=sec["节"], 条目=e["条目"], 探真行=e["行"],
|
||||
药=name, 名位=poss))
|
||||
return rows
|
||||
|
||||
|
||||
def judge_drugs(rows, oracle_tbl, thirteen):
|
||||
orc = {}
|
||||
for d in oracle_tbl:
|
||||
orc.setdefault(d["草木药"], dict(名位=set(), 类="药精·草木", 行=d["底本行"]))["名位"].add(d["名位"])
|
||||
orc.setdefault(d["金石药"], dict(名位=set(), 类="药精·金石", 行=d["底本行"]))["名位"].add(d["名位"])
|
||||
for t in thirteen:
|
||||
e = orc.setdefault(t["药"], dict(名位=set(), 类="十三种药", 行=t["底本行"]))
|
||||
e["名位"].update(t["名位"])
|
||||
unknown = []
|
||||
for r in rows:
|
||||
if not r["名位"]:
|
||||
r["判定"] = "— 无名位(第 2 章菜果谷畜/第七节录文:按方剂药行关联)"
|
||||
continue
|
||||
base = TZ2BASE.get(r["药"], "__MISS__")
|
||||
if base == "__MISS__":
|
||||
unknown.append(r["药"])
|
||||
r["判定"] = "⚠ 未入归一表"
|
||||
continue
|
||||
S = set(r["名位"])
|
||||
e = orc.get(base) if base else None
|
||||
if e:
|
||||
r["底本药"], r["底本类"], r["底本行"] = base, e["类"], e["行"]
|
||||
# 判定口径与第 1/3 章检查报告一致:同名相符 → 已裁定的同位对应(JUDGE_OVERRIDE)
|
||||
# → 抵牾 → 底本无此品(作者拟补)。**不自行扩张同位判定**(理石虽与石英同「土中火」,
|
||||
# 前轮仍判「作者拟补」,本表从之)。
|
||||
if e and S <= e["名位"]:
|
||||
r["判定"] = "✅ 相符"
|
||||
elif e:
|
||||
r["判定"] = (f"⚠ 抵牾(底本 {e['类']} L{e['行']}「{base}」作 "
|
||||
f"{'/'.join(sorted(e['名位']))})")
|
||||
else:
|
||||
r["判定"] = "○ 作者拟补/底本无此品(名位系作者自立)"
|
||||
ov = next((JUDGE_OVERRIDE[(r["药"], p)] for p in r["名位"]
|
||||
if (r["药"], p) in JUDGE_OVERRIDE), None)
|
||||
if ov and not r["判定"].startswith("✅"):
|
||||
r["判定"] = ov
|
||||
return orc, unknown
|
||||
|
||||
|
||||
# ── ③ 底本 64 首方 → 药味行 ─────────────────────────────────────────────
|
||||
def clean_token(p):
|
||||
p = re.sub(r"([^)]*)", "", p)
|
||||
p = DOSE.sub("", p)
|
||||
p = DOSE2.sub("", p).strip()
|
||||
prev = None
|
||||
while p and p != prev:
|
||||
prev = p
|
||||
p = CURED.sub("", p)
|
||||
return p.strip(",,、。;;:()")
|
||||
|
||||
|
||||
def is_drug_line(s):
|
||||
chunks = [c for c in re.split(r"[\s ]+", s) if c]
|
||||
if not chunks or max(len(c) for c in chunks) > 14:
|
||||
return False
|
||||
ok = sum(1 for c in chunks
|
||||
if DOSE.search(c) or (len(c) <= 6 and re.fullmatch(r"[\u4e00-\u9fa5]+", c.split(",")[0])))
|
||||
return ok >= len(chunks) * 0.7
|
||||
|
||||
|
||||
STOP_TOKEN = {"共为极细", "打", "捣如泥", "绵裹", "为末", "研", "取", "入", "洗", "炙", "熬",
|
||||
"切", "炮", "末", "擘", "碎", "烧", "煮", "去滑", "捣", "去节"}
|
||||
|
||||
|
||||
def tokens_of(s):
|
||||
return [x for x in (clean_token(p) for chunk in re.split(r"[\s ]+", s) for p in chunk.split(","))
|
||||
if x and x not in STOP_TOKEN and not re.fullmatch(r"[一二三四五六七八九十百半]+", x)]
|
||||
|
||||
|
||||
def build_fangs(lines, bendi_struct):
|
||||
names = {f["方名"] for f in bendi_struct["方"]}
|
||||
fangs = []
|
||||
for f in bendi_struct["方"]:
|
||||
comp, jia, qu, rows = [], [], [], []
|
||||
for i in range(f["起始行"], f["结束行"] + 1):
|
||||
s = lines[i - 1].strip()
|
||||
if not s or s.startswith(("右", "上", ">", "#", "附:")):
|
||||
continue
|
||||
m = re.match(r"^([^::]{2,14})[::](.*)$", s)
|
||||
if m and m.group(1) in names:
|
||||
s = m.group(2).strip()
|
||||
if "。" in s:
|
||||
s = s.split("。")[0]
|
||||
if not DOSE.search(s):
|
||||
continue
|
||||
if JIAJIAN.search(s):
|
||||
jia += [x for _, x in JIA.findall(s)]
|
||||
qu += QU.findall(s)
|
||||
rows.append(i)
|
||||
continue
|
||||
if is_drug_line(s):
|
||||
comp += tokens_of(s)
|
||||
rows.append(i)
|
||||
fangs.append(dict(篇=f["篇"], 方名=f["方名"], 组成=comp, 加=sorted(set(jia)),
|
||||
去=sorted(set(qu)), 药行=rows, 起始行=f["起始行"], 结束行=f["结束行"]))
|
||||
return fangs
|
||||
|
||||
|
||||
def tz_index(tz_struct):
|
||||
"""探真条目名 → (章, 节, 条目, 行);含子目名"""
|
||||
idx = {}
|
||||
for ch in tz_struct["章"]:
|
||||
for sec in ch["节"]:
|
||||
for e in sec["条目"]:
|
||||
head = re.sub(r"^[一二三四五六七八九十]+、", "",
|
||||
re.sub(r"([^)]*)", "", e["条目"])).strip()
|
||||
if head:
|
||||
idx.setdefault(head, dict(章=ch["章"], 节=sec["节"], 条目=e["条目"], 行=e["行"]))
|
||||
for name, _p in parse_entry(e["条目"]):
|
||||
idx.setdefault(name, dict(章=ch["章"], 节=sec["节"], 条目=e["条目"], 行=e["行"]))
|
||||
for sub in e.get("子目", []):
|
||||
nm = re.sub(r"^\d+\.\s*", "", sub["子目"])
|
||||
nm = re.sub(r"([^)]*)", "", nm).strip()
|
||||
if nm:
|
||||
idx.setdefault(nm, dict(章=ch["章"], 节=sec["节"], 条目=e["条目"],
|
||||
行=sub["行"], 子目=sub["子目"]))
|
||||
return idx
|
||||
|
||||
|
||||
def fang_citation_index(tz_lines, bendi_struct):
|
||||
"""方剂级:底本 64 方名 → 探真正文命中行(全名 / 去「小」「大」前缀之简称 分别记)"""
|
||||
out = []
|
||||
for f in bendi_struct["方"]:
|
||||
nm = f["方名"]
|
||||
stem = re.sub(r"([^)]*)", "", nm)
|
||||
core = re.sub(r"(散汤|汤散|汤|散)$", "", stem)
|
||||
full = {nm, stem} | {core + x for x in ("汤", "散", "汤散", "散汤")}
|
||||
short = {re.sub(r"^[小大]", "", c) for c in full}
|
||||
short = {c for c in short - full if len(c) >= 3}
|
||||
full = {c for c in full if len(c) >= 3}
|
||||
hits, hits_short, near = [], [], []
|
||||
for i, l in enumerate(tz_lines, 1):
|
||||
fh = next((c for c in sorted(full, key=len, reverse=True) if c in l), None)
|
||||
if fh:
|
||||
hits.append((i, fh))
|
||||
continue
|
||||
sh = next((c for c in sorted(short, key=len, reverse=True) if c in l), None)
|
||||
if sh:
|
||||
hits_short.append((i, sh))
|
||||
if not hits and not hits_short and len(core) >= 2:
|
||||
tail = core[-2:]
|
||||
for i, l in enumerate(tz_lines, 1):
|
||||
k = l.find(tail)
|
||||
if k >= 0:
|
||||
near.append((i, l[max(0, k - 3):k + len(tail) + 1]))
|
||||
out.append(dict(方名=nm, 篇=f["篇"], 全名候选=sorted(full), 简称候选=sorted(short),
|
||||
命中=hits, 简称命中=hits_short, 近似=near[:4]))
|
||||
return out
|
||||
|
||||
|
||||
def main():
|
||||
check_only = "--check" in sys.argv
|
||||
btext, bmd5 = read(BENDI_MD)
|
||||
blines = btext.split("\n")
|
||||
ttext, tmd5 = read(TZ_MD)
|
||||
tlines = ttext.split("\n")
|
||||
bstruct = json.loads(read(BENDI_JSON)[0])
|
||||
tstruct = json.loads(read(TZ_JSON)[0])
|
||||
|
||||
oracle_tbl, thirteen = parse_oracle(blines)
|
||||
rows = build_drug_rows(tstruct)
|
||||
orc, unknown = judge_drugs(rows, oracle_tbl, thirteen)
|
||||
fangs = build_fangs(blines, bstruct)
|
||||
tidx = tz_index(tstruct)
|
||||
cites = fang_citation_index(tlines, bstruct)
|
||||
|
||||
# ── 药—方—阐释:底本各方药味 → 探真条目 ──
|
||||
for f in fangs:
|
||||
link = []
|
||||
for d in f["组成"]:
|
||||
v = BASE2TZ.get(d, "__MISS__")
|
||||
if v == "__MISS__":
|
||||
v = d if d in tidx else None # 方中药名即探真条目名者,直接命中
|
||||
tzn = v
|
||||
hit = tidx.get(tzn) if tzn else None
|
||||
link.append(dict(底本药=d, 探真条目=tzn if tzn else "(探真未收)",
|
||||
位置=(f"{hit['章'][:3]}·{hit['节'][:3]}·{hit['条目'][:14]} 行{hit['行']}"
|
||||
if hit else None)))
|
||||
f["药—阐释"] = link
|
||||
|
||||
# ── 自检 ──
|
||||
checks = []
|
||||
checks.append(("底本 baseline md5 与冻结值一致(未动底本)", bmd5 == BENDI_MD5))
|
||||
checks.append(("探真合卷本 md5 与登记值一致", tmd5 == TZ_MD5))
|
||||
checks.append(("药精表 25 条、十三种药 13 条", len(oracle_tbl) == 25 and len(thirteen) == 13))
|
||||
checks.append(("底本 64 首方全部定位", len(fangs) == 64))
|
||||
n_full = sum(1 for l in cites if l["命中"])
|
||||
n_short = sum(1 for l in cites if not l["命中"] and l["简称命中"])
|
||||
n_none = sum(1 for l in cites if not l["命中"] and not l["简称命中"])
|
||||
checks.append((f"方剂级反向索引:全名直引 {n_full} 方 · 简称命中 {n_short} 方 · 未引及 {n_none} 方", True))
|
||||
checks.append(("归一表覆盖:探真药物级行全部可判",
|
||||
all(r["判定"] != "⚠ 未入归一表" for r in rows)))
|
||||
checks.append(("药精表 25 名位与探真第 1/3 章五节一一对应",
|
||||
len({d["名位"] for d in oracle_tbl}) == 25))
|
||||
named = [r for r in rows if r["名位"]]
|
||||
rowc = collections.Counter(re.split(r"[((]", r["判定"])[0].strip() for r in named)
|
||||
checks.append((f"药物级 {len(named)} 行(按「药」行计,另含 "
|
||||
f"{sum(len(r['名位']) for r in named)} 个「名位」标记):"
|
||||
+ " · ".join(f"{k} {v}" for k, v in rowc.most_common()), True))
|
||||
ch1_ok = sum(1 for r in named if r["章"].startswith("第一章") and r["判定"].startswith("✅"))
|
||||
ch3_ok = sum(1 for r in named if r["章"].startswith("第三章") and r["判定"].startswith("✅"))
|
||||
checks.append((f"与前轮报告口径对照(粒度更细,判定一致):第 1 章 ✅ {ch1_ok}/第 3 章 ✅ {ch3_ok}"
|
||||
f"(前轮报告:第 1 章 34 相符·1 待核·1 另论;第 3 章 29 相符·6 拟补·0 抵牾)", True))
|
||||
miss_yao = sorted({l["底本药"] for f in fangs for l in f["药—阐释"] if l["位置"] is None})
|
||||
checks.append((f"方中药味未能串到探真释义者 {len(miss_yao)} 种(登记为缺口)", True))
|
||||
ok = all(v for _, v in checks)
|
||||
|
||||
diff = []
|
||||
for r in named:
|
||||
if r["判定"].startswith("⚠ 抵牾"):
|
||||
e = orc.get(r.get("底本药") or "", dict(名位=set()))
|
||||
bad = [p for p in r["名位"] if p not in e["名位"]] or r["名位"]
|
||||
diff.append(("D1 名位抵牾", f"{r['章'][:3]} {r['条目']} · {r['药']} {'/'.join(bad)}", r["判定"]))
|
||||
for r in named:
|
||||
if r["判定"].startswith("○"):
|
||||
diff.append(("D2 底本无对应(作者拟补)", f"{r['章'][:3]} {r['条目']} · {r['药']}",
|
||||
"/".join(r["名位"]) + "(底本《汤液经法》二十五味药精/十三种药无此品)"))
|
||||
for f in fangs:
|
||||
if not f["组成"]:
|
||||
diff.append(("D3 药行未识别", f"{f['篇']} · {f['方名']}", "药名散在用法散文中,未机械切分"))
|
||||
diff += [(c, o, d) for c, o, d in WORD_NOTES]
|
||||
for l in cites:
|
||||
if not l["命中"] and not l["简称命中"]:
|
||||
diff.append(("D4 探真未引及", l["篇"] + " · " + l["方名"],
|
||||
"探真第 1–3 章正文无此方名(含去「小/大」前缀之简称);"
|
||||
+ ("近似上下文:" + ";".join(f"L{h}「…{c}…」" for h, c in l["近似"])
|
||||
if l["近似"] else "亦无近似上下文")))
|
||||
|
||||
# ── 渲染 ──
|
||||
def anchor(rel):
|
||||
return f"`{rel}`(md5 `{md5_of(os.path.join(BASE, rel))}`)"
|
||||
|
||||
tbl = [f"# 《药性探真》第 1–3 章 ⇄ 《辅行诀五脏用药法要》底本 — 药名·方目对照表", "",
|
||||
"> **主从**:主=底本《辅行诀五脏用药法要》(印刷本,baseline,用户 2026-09-16 定为基础);"
|
||||
"从=《药性探真》第 1–3 章合卷本(研究文献,级别低于底本)。",
|
||||
"> **铁律**:**差异只登记,不改任何一方原文**;行号一律指各自清洗版;锚校验唯一命中。",
|
||||
"> 📅 2026-09-22 建(用户指令:「初步进行…数据关联,《辅行诀五脏用药法要》作为古本,是基础」)", "",
|
||||
"## 一、来源与锚", "",
|
||||
"| 侧 | 文件 | md5 |", "|----|------|-----|",
|
||||
f"| 主·底本 | {anchor(BENDI_MD)} | |".replace(" | |", " |"),
|
||||
f"| 从·探真合卷 | {anchor(TZ_MD)} | |".replace(" | |", " |"),
|
||||
f"| 底本结构 | `{BENDI_JSON}`(篇 {len(bstruct['篇'])} · 方 {len(bstruct['方'])}) | |".replace(" | |", " |"),
|
||||
f"| 探真结构 | `{TZ_JSON}`(章 3 · 条目 {sum(len(s['条目']) for c in tstruct['章'] for s in c['节'])}) | |".replace(" | |", " |"),
|
||||
"",
|
||||
"**底本锚**:《汤液经法》二十五味药精=L415/417/419/421/423;十三种药=L429。",
|
||||
"**探真锚**:合卷本行号(=该章清洗版行号 + 偏移 2/1018/1680)。", "",
|
||||
"## 二、药物级对位(探真条目「药名+名位」⇄ 底本药精/十三种药)", "",
|
||||
"| 探真章 | 探真节 | 探真条目 | 药 | 探真名位 | 底本依据 | 判定 |",
|
||||
"|--------|--------|---------|----|---------|---------|------|"]
|
||||
for r in rows:
|
||||
base = r.get("底本药", "")
|
||||
if r.get("底本类") and r.get("底本行"):
|
||||
e = orc[base]
|
||||
ev = f"底本 {r['底本类']} L{r['底本行']}「{base}」:{'/'.join(sorted(e['名位']))}"
|
||||
elif r["判定"].startswith("○"):
|
||||
ev = "底本《汤液经法》无此品"
|
||||
else:
|
||||
ev = "—"
|
||||
tbl.append(f"| {r['章'][:3]} | {r['节'][:6]} | {r['条目'][:22]} | {r['药']} | "
|
||||
f"{'/'.join(r['名位']) or '—'} | {ev} | {r['判定']} |")
|
||||
tbl += ["", "## 三、方剂级反向索引(底本 64 首方名 ⇄ 探真正文引用)", "",
|
||||
"> 探真为**研究文献**,正文引方名常作**简称**(去「小/大」前缀,如底本「小养生补肝汤散」"
|
||||
"→探真「养生补肝汤」);下表分列**全名直引**与**简称命中**,未命中者给近似上下文。", "",
|
||||
"| 底本篇 | 方名 | 全名命中行 | 简称命中行 | 近似上下文 |", "|--------|------|-----------|-----------|-----------|"]
|
||||
for l in cites:
|
||||
hf = "、".join(str(h) for h, _ in l["命中"][:10]) + ("…" if len(l["命中"]) > 10 else "")
|
||||
hs = "、".join(f"{h}({c})" for h, c in l["简称命中"][:6]) + ("…" if len(l["简称命中"]) > 6 else "")
|
||||
nr = ";".join(f"L{h}「…{c}…」" for h, c in l["近似"]) or "—"
|
||||
tbl.append(f"| {l['篇'][:20]} | {l['方名']} | {hf or '—'} | {hs or '—'} | {nr} |")
|
||||
tbl += ["", "## 四、药—方—阐释 三级串联(底本每首方 → 各药 → 探真释义位置)", "",
|
||||
"| 方名 | 药味(组成) | 各药在探真中的释义位置 |", "|------|------------|---------------------|"]
|
||||
for f in fangs:
|
||||
if not f["组成"]:
|
||||
continue
|
||||
cells = ";".join(f"{l['底本药']}→{l['位置'] or '**(探真未收)**'}" for l in f["药—阐释"])
|
||||
tbl.append(f"| {f['方名']} | {' '.join(f['组成'])} | {cells} |")
|
||||
tbl += ["", "## 五、差异清单(只登记,不校改)", "", "| 类 | 对象 | 说明 |", "|----|------|------|"]
|
||||
for c, o, d in diff:
|
||||
tbl.append(f"| {c} | {o} | {d} |")
|
||||
tbl += ["", "## 六、自检", ""]
|
||||
for n, v in checks:
|
||||
tbl.append(f"- {'✅' if v else '❌'} {n}")
|
||||
tbl += ["", "## 七、未落位登记(不藏失败)", "",
|
||||
f"- 方中药味未能串到探真释义者({len(miss_yao)} 种):" + ("、".join(miss_yao) or "无"),
|
||||
f"- 底本 64 方中探真未引及者(含简称):"
|
||||
+ ("、".join(l['方名'] for l in cites if not l['命中'] and not l['简称命中']) or "无"),
|
||||
f"- 探真条目中底本无对应(作者拟补/底本另论):"
|
||||
+ ("、".join(sorted({r['药'] for r in named if r['判定'].startswith('○')})) or "无"), ""]
|
||||
|
||||
rep = ["# 《药性探真》⇄ 底本 — 核对报告(初步数据关联)", "",
|
||||
"> 📅 2026-09-22|用户指令:「初步进行《辅行诀五脏用药法要》与《…药性探真》的数据关联,"
|
||||
"《辅行诀五脏用药法要》作为古本,是基础」。",
|
||||
"> 主从:**主=底本(印刷本 baseline)**,**从=探真合卷本(研究文献)**;"
|
||||
"**差异只登记、不改任何一方原文**。", "",
|
||||
"## 一、结论摘要", "", "| 项 | 结果 |", "|----|------|",
|
||||
f"| 药物级对位 | 探真有名位「药」行 **{len(named)}** 行(含 "
|
||||
f"{sum(len(r['名位']) for r in named)} 个名位标记)→ "
|
||||
+ " · ".join(f"{k} {v}" for k, v in collections.Counter(
|
||||
re.split(r"[((]", r["判定"])[0].strip() for r in named).most_common()) + " |",
|
||||
f"| 方剂级反向索引 | 底本 64 方 → **全名直引 {n_full} 方** · **简称命中 {n_short} 方** · "
|
||||
f"**未引及 {n_none} 方**(详见《对照表》第三节) |",
|
||||
f"| 药—方—阐释串联 | 底本 64 方中 {sum(1 for f in fangs if f['组成'])} 方切出药味;"
|
||||
f"未识别 {sum(1 for f in fangs if not f['组成'])} 方 |",
|
||||
f"| 用字/体例差异 | D5 共 {sum(1 for c,_,_ in diff if c.startswith('D5'))} 条(只登记、不校改;见差异清单) |",
|
||||
f"| 差异登记 | D1 名位抵牾 {sum(1 for c,_,_ in diff if c.startswith('D1'))} · "
|
||||
f"D2 底本无对应 {sum(1 for c,_,_ in diff if c.startswith('D2'))} · "
|
||||
f"D3 药行未识别 {sum(1 for c,_,_ in diff if c.startswith('D3'))} · "
|
||||
f"D4 探真未引及 {sum(1 for c,_,_ in diff if c.startswith('D4'))} |", "",
|
||||
"## 二、对位规则", "",
|
||||
"1. **药物级**:探真条目题名的「(X中Y)」为**待验断言**,与底本《汤液经法》"
|
||||
"二十五味药精/十三种药逐条互证(本库第 1/3 章检查报告已用同一口径,此处汇总并扩展至全 3 章)。",
|
||||
"2. **同名对应**:探真药名与底本药名经**显式归一表**(TZ2BASE)对位,不用模糊匹配。",
|
||||
"3. **同位对应**:探真之金石(或草木)药若与底本某草木(或金石)药**名位对完全相同**,"
|
||||
"判「✅ 相符(同位对应)」并注明同位依据(如铁落⇄通草、石蜜⇄升麻、石胆⇄淡豆豉、曾青⇄五味子)。",
|
||||
"4. **方剂级**:以底本 64 方名(含归一候选)扫探真合卷正文,建**反向索引**(探真何处引此方)。",
|
||||
"5. **药—方—阐释**:底本每方药味行切出药味(剥离剂量与炮制),经 BASE2TZ 串到探真条目行号。",
|
||||
"6. **差异只登记**:名位抵牾、作者拟补、药行未识别、探真未引及,一律入差异清单,不校改任何一方。",
|
||||
"",
|
||||
"> ⚠ **粒度口径**:本表粒度=**「药·名位」**(比第 1/3 章检查报告之「条目」粒度更细——"
|
||||
"同一多药条目会拆成数行);判定口径与前两章一致:同名相符/已裁定的同位对应/抵牾/作者拟补。"
|
||||
"**同位判定不自行扩张**:理石虽与底本石英同「土中火」,前轮判「作者拟补」,本表从之。", "",
|
||||
"## 三、差异清单", "", "| 类 | 对象 | 说明 |", "|----|------|------|"]
|
||||
for c, o, d in diff:
|
||||
rep.append(f"| {c} | {o} | {d} |")
|
||||
rep += ["", "## 四、关联用法", "",
|
||||
"1. 查某味药:在《对照表》第二节按药名检索,得探真释义行号(合卷本)与底本依据行号。",
|
||||
"2. 查某首方:第三节给探真正文引用行;第四节给该方各药在探真中的释义位置。",
|
||||
"3. **引用纪律**:底本为**主**,探真为**从**(研究文献)——凡方药组成、剂量、篇次,"
|
||||
"一律引底本;探真的「X中Y」名位与释义只作理论阐释与旁证,**不得以探真替代底本**。", "",
|
||||
"## 五、缺口与待决(带优先级)", "",
|
||||
"| 优先级 | 事项 | 建议动作 |", "|--------|------|---------|",
|
||||
"| 高 | 名位抵牾 1 处(五味子「金中火」) | 本库第 1 章清单 #8 已判「暂留待核」;如核对原书可定案 |",
|
||||
"| 中 | 中恶卒死方 6 首药行未机械切分(药名在用法散文中) | 如需入表,另立「用法体方」人工核定表 |",
|
||||
f"| 中 | 方中药味探真未收者({'、'.join(miss_yao) or '无'}) | 属探真取材范围(第 1–3 章)之外,登记为缺口,待附录补入 |",
|
||||
"| 低 | 探真未引及之方(见《对照表》第七节) | 多为救误方与附录拟补方,可作后续挖掘线索 |", "",
|
||||
"## 六、产物", "",
|
||||
f"- `{OUT_TABLE}`(人读)/`{OUT_JSON}`(机器读)/本报告",
|
||||
f"- 脚本 `05_脚本工具/15_link_tanzhen.py`(幂等;`--check` 只校验不写盘)", ""]
|
||||
|
||||
struct = dict(
|
||||
定位="《药性探真》第 1–3 章 ⇄ 《辅行诀五脏用药法要》底本 初步数据关联",
|
||||
主从="主=底本(印刷本 baseline,用户 2026-09-16 定为基础);从=探真合卷本(研究文献,级别低于底本)",
|
||||
粒度="药物级(药名+五味五行互含名位)/方剂级(方名反向索引)/药—方—阐释 三级串联",
|
||||
用户指令="2026-09-22「初步进行《辅行诀五脏用药法要》与《辅行诀五脏用药法要 药性探真》的数据关联,"
|
||||
"《辅行诀五脏用药法要》作为古本,是基础」",
|
||||
来源=dict(底本文件=BENDI_MD, 底本md5=bmd5, 底本结构=BENDI_JSON,
|
||||
探真文件=TZ_MD, 探真md5=tmd5, 探真结构=TZ_JSON),
|
||||
底本锚=dict(二十五味药精=[ln for ln, _ in YAO_ANCHORS], 十三种药=THIRTEEN_LINE),
|
||||
药精表=oracle_tbl, 十三种药=thirteen,
|
||||
药物级对位=[dict(章=r["章"], 节=r["节"], 条目=r["条目"], 探真行=r["探真行"], 药=r["药"],
|
||||
名位=r["名位"], 底本药=r.get("底本药"), 底本类=r.get("底本类"),
|
||||
底本行=r.get("底本行"), 判定=r["判定"]) for r in rows],
|
||||
方剂级反向索引=[dict(篇=l["篇"], 方名=l["方名"],
|
||||
全名命中行=[h for h, _ in l["命中"]],
|
||||
简称命中行=[h for h, _ in l["简称命中"]],
|
||||
近似上下文=[dict(行=h, 文=c) for h, c in l["近似"]]) for l in cites],
|
||||
药方阐释=[dict(篇=f["篇"], 方名=f["方名"], 组成=f["组成"], 加=f["加"], 去=f["去"],
|
||||
药行=f["药行"], 关联=f["药—阐释"]) for f in fangs],
|
||||
差异清单=[dict(类=c, 对象=o, 说明=d) for c, o, d in diff],
|
||||
未落位=dict(方中药味探真未收=miss_yao,
|
||||
探真未引及之方=[l["方名"] for l in cites if not l["命中"] and not l["简称命中"]],
|
||||
底本无对应之探真药=sorted({r["药"] for r in named if r["判定"].startswith("○")})),
|
||||
自检=[dict(项=n, 结果="✅ 通过" if v else "❌ 未通过") for n, v in checks],
|
||||
重跑="python3 05_脚本工具/15_link_tanzhen.py(幂等;--check 只校验)",
|
||||
)
|
||||
|
||||
if not ok:
|
||||
print("❌ 自检未通过,未写盘:")
|
||||
for n, v in checks:
|
||||
if not v:
|
||||
print(" -", n)
|
||||
return 1
|
||||
if check_only:
|
||||
print("--check:自检通过,未写盘。")
|
||||
for n, _ in checks:
|
||||
print(" ✅", n)
|
||||
return 0
|
||||
|
||||
wf(OUT_TABLE, "\n".join(tbl) + "\n")
|
||||
wf(OUT_REPORT, "\n".join(rep) + "\n")
|
||||
wf(OUT_JSON, json.dumps(struct, ensure_ascii=False, indent=2) + "\n")
|
||||
print("对照表:", OUT_TABLE, os.path.getsize(os.path.join(BASE, OUT_TABLE)), "bytes")
|
||||
print("报告 :", OUT_REPORT, os.path.getsize(os.path.join(BASE, OUT_REPORT)), "bytes")
|
||||
print("JSON :", OUT_JSON, os.path.getsize(os.path.join(BASE, OUT_JSON)), "bytes")
|
||||
print(f"药物级 {len(rows)} 行(有名位 {len(named)})|方剂级 {len(cites)} 方|方—药 {len(fangs)} 方")
|
||||
for n, v in checks:
|
||||
print(" ✅", n)
|
||||
print(" ⓘ 方中药味探真未收:", "、".join(miss_yao) or "无")
|
||||
print(f" ⓘ 方剂级:全名直引 {n_full} · 简称命中 {n_short} · 未引及 {n_none}")
|
||||
print(" ⓘ 探真未引及之方:",
|
||||
"、".join(l["方名"] for l in cites if not l["命中"] and not l["简称命中"]) or "无")
|
||||
for rel in (OUT_TABLE, OUT_REPORT, OUT_JSON):
|
||||
print(f" md5 {md5_of(os.path.join(BASE, rel))} {rel}")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Reference in new issue
Block a user