初始归档:健康管理资料库(大医网/药膳/体质监测/中医理论等12个资料集,7712个文件)

This commit is contained in:
512song committed 2026-09-23 21:59:25 +08:00
commit 80ae3811cf
7712 files changed
+4628547

No files matched your search

@@ -0,0 +1,90 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""01_merge_sunben.py — 《神农本草经·清·孙星衍》(殆知阁本) 合并整理版生成
规则(2026-09-22 用户指令):
1. 重复出现的「卷一/二/三 上/中/下经」卷标行只保留一次(同卷连续出现的合并);
2. 药物条目块(药名单行+味…+吴普/名医/案)合并为组织化结构,药名转为 ####;
3. 原件正文一字不改,仅做结构性合并(去重卷标、条目并块、空行规整);
4. 幂等可重跑;输出至 校核参考/殆知阁-孙星衍辑本/神农本草经_孙星衍辑本_合并整理版.md
"""
import re, sys, json, hashlib, os
BASE = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # 01_来源数据/..
SRC = os.path.join(BASE, '01_来源数据', '校核参考', '殆知阁-孙星衍辑本',
'神农本草经_孙星衍辑本_原文快照_20260922.md')
OUT = os.path.join(BASE, '01_来源数据', '校核参考', '殆知阁-孙星衍辑本',
'神农本草经_孙星衍辑本_合并整理版.md')
STAT = os.path.join(BASE, '01_来源数据', '校核参考', '殆知阁-孙星衍辑本',
'合并整理版_结构.json')
VOL_RE = re.compile(r'^卷([一二三四])\s* ?\s*([上中下])经$')
def build(lines):
out, cur_vol, stat = [], None, {'卷标原始出现': 0, '卷标合并保留': 0, '药条': 0, '序录行': 0}
i, n = 0, len(lines)
# frontmatter 与前言按原样保留
buf = []
while i < n:
raw = lines[i]
s = raw.strip()
m = VOL_RE.match(s)
if m:
stat['卷标原始出现'] += 1
vol = f'## 卷{m.group(1)} {m.group(2)}经'
# 判断此卷标行是否为重复标记:其前方上一非空行若同卷经 -> 跳过
prev_nonempty = next((l.strip() for l in reversed(buf) if l.strip()), '')
if prev_nonempty_still_diff(vol, buf):
pass
if cur_vol == vol:
i += 1
continue # 重复卷标,合并
cur_vol = vol
buf.append('')
buf.append('---')
buf.append(vol)
buf.append('')
stat['卷标合并保留'] += 1
i += 1
continue
# 药名行:非空、短、无句号,且下一非空行以「味」或「KT」开头
if s and cur_vol and len(s) <= 12 and s not in ('(原注:上此五条,出《药对》中,义旨渊深,非俗所究。虽莫可遵用,而是主统之本,故亦载之。)',):
nxt = next((l.strip() for l in lines[i+1:] if l.strip()), '')
nxt_is_body = nxt.startswith('味') or nxt == 'KT'
if nxt_is_body and not s.endswith(('。',)) and not s.startswith('《'):
buf.append(f'#### {s}')
stat['药条'] += 1
i += 1
continue
buf.append(raw.rstrip())
i += 1
out = buf
return out, stat
def prev_nonempty_still_diff(vol, buf):
return False
def main():
src_text = open(SRC, encoding='utf-8').read()
lines = src_text.split('\n')
body, stat = build(lines)
text = '\n'.join(body)
# 空行规整:连续3+空行→1空行(结构性,不改文字)
text = re.sub(r'\n{4,}', '\n\n\n', text)
open(OUT, 'w', encoding='utf-8').write(text)
md5 = hashlib.md5(open(OUT, 'rb').read()).hexdigest()
stat['md5'] = md5
stat['bytes'] = os.path.getsize(OUT)
stat['行数'] = text.count('\n') + 1
# 药条按卷统计
sec, cnt = None, {'卷一 上经': 0, '卷二 中经': 0, '卷三 下经': 0}
for l in text.split('\n'):
s = l.strip()
m = VOL_RE.match(s) or (s.startswith('## ') and VOL_RE.match(s[3:]))
if m: sec = f'卷{m.group(1)}\u3000{m.group(2)}经'
elif s.startswith('#### ') and sec in cnt: cnt[sec] += 1
stat['药条_按卷'] = cnt
json.dump(stat, open(STAT, 'w', encoding='utf-8'), ensure_ascii=False, indent=1)
print(json.dumps(stat, ensure_ascii=False, indent=1))
if __name__ == '__main__':
main()
@@ -0,0 +1,138 @@
# -*- coding: utf-8 -*-
"""03_compare_two_refs.py — 殆知阁孙本(第一参照本) ⇄ 维基文库(第二参校本) 初步对照
三层分离:①名称对齐层(显式异体映射,对照键不改原文)→ ②繁简/标点规整层(对照镜像)→ ③实字异文层(只登记)。
原则:两参校本任意一方都不改原文;差异全部登记 02_加工数据/产物。"""
import re, json, os, difflib
BASE = '/home/songyi/Documents/ai_agent_scraper_study/data/神农本草经'
SUN = os.path.join(BASE, '01_来源数据/校核参考/殆知阁-孙星衍辑本/神农本草经_孙星衍辑本_合并整理版.md')
WK = os.path.join(BASE, '01_来源数据/校核参考/维基文库/神农本草经_快照_20260922.md')
def splitdrug_sun(text):
drugs = {}
cur = None
for l in text.split('\n'):
s = l.strip()
if s.startswith('#### '):
cur = s[5:].strip(); drugs.setdefault(cur, [])
elif s.startswith('## '):
cur = None
elif cur is not None and s:
drugs[cur].append(s)
return drugs
def splitdrug_wk(text):
drugs = {}
for l in text.split('\n'):
s = l.strip()
if s.startswith('#') or not s or '\u3000' not in s:
continue
name, body = s.split('\u3000', 1)
drugs.setdefault(name.strip(), body)
return drugs
ALIAS = dict([
('丹沙','丹砂'),('丹參','丹参'),('丹雄雞','丹雄鸡'),('乾地黃','干地黄'),('乾漆','干漆'),
('乾薑','干姜'),('五味','五味子'),('人參','人参'),('假蘇','假苏'),('別羈','别羁'),
('厚朴','浓朴'),('合歡','合欢'),('商陸','商陆'),('地膚子','地肤子'),('地膽','地胆'),
('大棗','大枣'),('大豆黃卷','大黄豆卷'),('大黃','大黄'),('天門冬','天门冬'),
('太一禹余糧','太乙余粮'),('女菀','女萎'),('女貞實','女贞实'),
('慈石','磁石'),('敗醬','败酱'),('旋覆花','旋复花'),
('朮','术'),('朴消','朴硝'),('杏核','杏核仁'),('柏實','柏实'),('柳華','柳花'),
('栝樓','栝蒌根'),('桃核','桃核仁'),('槐子','槐实'),('練實','楝实'),('款冬','款冬花'),
('水斳','水靳'),('決明子','决明子'),('沙參','沙参'),('消石','硝石'),('澤漆','泽漆'),
('澤瀉','泽泻'),('澤蘭','泽兰'),('烏賊魚骨','乌贼鱼骨'),('烏韭','乌韭'),('烏頭','乌头'),
('營實','营实'),('牛黃','牛黄'),('牡蠣','牡蛎'),('狗陰莖','牡狗阴茎'),('狼毒','野狼毒'),
('猬皮','猥皮'),('獨活','独活'),('玄參','元参'),('當歸','当归'),('白僵蠶','白僵蚕'),
('白堊','白垩'),('白膠','白胶'),('白蘞','白蔹'),('白鮮','白藓'),('白馬莖','白马茎'),
('皂莢','皂荚'),('瞿麥','瞿麦'),('石南草','石南'),('石鐘乳','石钟乳'),('石龍子','石龙子'),
('石龍芮','石龙芮'),('石龍芻','石龙刍'),('石韋','石苇'),('石長生','石长生'),
('秦椒','秦菽'),('積雪草','积雪草'),('竹葉','竹叶'),('粉錫','粉锡'),('紫參','紫参'),
('續斷','续断'),('羊躑躅','羊踯躅'),('肉松容','肉松蓉'),('芍藥','芍药'),
('芎藭','芎藭'),('苦參','苦参'),('茈胡','柴胡'),
('莧實','苋实'),('莨蕩子','莨荡子'),('葈耳實','耳实'),('蒲陶','葡萄'),
('蒲黃','蒲黄'),('蒿本','蒿本'),('蓼實','蓼实'),('蔓荊實','蔓荆实'),
('蔥實','葱实'),('蕘華','荛花'),('蕪荑','芜荑'),('薇銜','薇衔'),('薏苡人','薏苡仁'),
('藕實莖','藕实茎'),('藍實','蓝实'),('藎草','荩草'),('蘼蕪','蘼芜'),('蚱蟬','柞蝉'),
('蛇蛻','蛇蜕'),('蠐螬','蛴螬'),('蜜蠟','蜜蜡'),('蜣蜋','蜣螂'),('蝦蟇','虾蟆'),
('螢火','荧火'),('螻蛄','蝼蛄'),('蠡實','蠡实'),('衛矛','卫矛'),
('衣魚','衣鱼'),('貝子','贝子'),('貝母','贝母'),('貫眾','贯众'),('車前子','车前子'),
('連翹','连翘'),('遠志','远志'),('郁核','郁李仁'),('酸棗','酸枣'),('酸醬','酸酱'),
('鉛丹','铅丹'),('長石','长石'),('防風','防风'),('阿膠','阿胶'),('陸英','陆英'),
('陽起石','阳起石'),('雀甕','雀瓮'),('雄黃','雄黄'),('雌黃','雌黄'),
('雞頭','鸡头实'),('雲實','云实'),('雲母','云母'),('青瑯玕','青琅玕'),('青葙','青葙子'),
('鞠華','鞠华'),('飛廉','飞廉'),('馬先蒿','马先蒿'),('馬刀','马刀'),('馬陸','马陆'),
('鮀魚甲','鮀鱼甲'),('鯉魚膽','鲤鱼膽'),('鱉甲','鳖甲'),('鳶尾','鳶尾'),('麥門冬','麦门冬'),
('麻蕡','麻贲'),('麻黃','麻黄'),('黃環','黄环'),('黃芩','黃芩'),('黃連','黄连'),
('鼠婦','鼠妇'),('龍眼','龙眼'),('龍膽','龙膽'),('龍骨','龙骨'),('龜甲','龟甲'),
('白頭公','白头翁'),
('蘭草','兰草'),('髮髲','发'),('太乙余粮','太乙余食'),
('旋華','旋华'),('木蘭','木蘭'),('松蘿','松萝'),('析蓂子','析蓂子'),
('欒華','欒花'),('桐葉','桐葉'),('梅實','梅實'),('樗雞','樗雞'),('水銀','水銀'),
('漏蘆','漏蘆'),('鷰屎','鷰屎'),('狼牙','狼牙'),('王孫','王孫'),
('豬苓','豬苓'),('螌蝥','班苗'),
('甘瓜子','甘瓜子'),
('石蠶','石蠶'),('禹余糧','禹余糧'),('紫石','紫石英'),
('細辛','細辛'),('絡石','絡石'),('膚青','膚青'),('芫華','芫華'),('藥食根','藥實根'),
('箘桂','菌桂'),('著實','著實'),
('白頸蚯蚓','白頸蚯蚓'),('蜀椒','蜀椒'),('吳公','吳公'),('石灰','石灰'),
])
import importlib, sys
spec = importlib.util.find_spec('opencc')
if spec:
from opencc import OpenCC
cc = OpenCC('t2s')
def t2s(s): return cc.convert(s)
else:
def t2s(s): return s
def punct_norm(s):
s = re.sub(r'[\s\u3000]+', '', s)
s = re.sub(r'([^)]*)|\([^)]*\)', '', s)
s = re.sub(r'[,。、;:!?,.;:!?]', '', s)
return s
sun_text = open(SUN, encoding='utf-8').read()
wk_text = open(WK, encoding='utf-8').read()
sd_raw = splitdrug_sun(sun_text)
wd_raw = splitdrug_wk(wk_text)
# 孙本经文=药条内「味…」段与紧随非吴普名医案的段;对照键取全部段落拼接但去掉吴普/名医/案部分
SUN_BODY_STOP = re.compile(r'^(《吴普|《名医|案:|《太平御览》引)')
sd = {}
for name, paras in sd_raw.items():
body = []
for p in paras:
if p.startswith('《吴普') or p.startswith('《名医》') or p.startswith('案:'):
break
body.append(p)
sd[name] = t2s(SUN_BODY_STOP and punct_norm(''.join(body)))
wd = {ALIAS.get(n, n): t2s(punct_norm(b)) for n, b in wd_raw.items()}
matched = sorted(set(sd) & set(wd))
same, diff_items = [], []
diff_detail = {}
for n in matched:
if sd[n] == wd[n]:
same.append(n)
else:
diff_items.append(n)
sm = difflib.SequenceMatcher(None, sd[n], wd[n], autojunk=False)
frag = []
for op, a1, a2, b1, b2 in sm.get_opcodes():
if op != 'equal':
frag.append({'op': op, '孙': sd[n][a1:a2], '维基': wd[n][b1:b2]})
diff_detail[n] = frag
print('对齐条目:', len(matched), ';同文:', len(same), ';异文:', len(diff_items))
print('仅孙本:', len(set(sd)-set(wd)), ';仅维基:', len(set(wd)-set(sd)))
json.dump({'同文': same, '异文条目': diff_items,
'未对齐_仅孙本': sorted(set(sd)-set(wd)), '未对齐_仅维基': sorted(set(wd)-set(sd)),
'异文明细': diff_detail},
open(os.path.join(BASE, '02_加工数据/参校本对照_药目核对.json'), 'w', encoding='utf-8'),
ensure_ascii=False, indent=1)
print('已写出 02_加工数据/参校本对照_药目核对.json')
# 摘样
for n in diff_items[:10]:
print('■', n, json.dumps(diff_detail[n][:4], ensure_ascii=False))
@@ -0,0 +1,23 @@
import json
d = json.load(open('02_加工数据/参校本对照_药目核对.json', encoding='utf-8'))
det = d['异文明细']
BOILER = {'治', '无毒', '有毒', '小', '微', '寒', '大寒'}
substantive = {}
for name, frags in det.items():
real = []
for f in frags:
s, w = f['孙'], f['维基']
if s == '' and w in BOILER:
continue
if w == '' and s in BOILER:
continue
real.append(f)
if real:
substantive[name] = real
print('实字异文条目(粗):', len(substantive), '/ 总异文', len(det))
for n in list(substantive)[:25]:
line = '; '.join("孙[%s]→维[%s]" % (f['孙'], f['维基']) for f in substantive[n][:5])
print('■', n, '|', line[:140])
json.dump(substantive, open('02_加工数据/_tmp_实字异文.json', 'w', encoding='utf-8'),
ensure_ascii=False, indent=1)
print('已写 02_加工数据/_tmp_实字异文.json')
@@ -0,0 +1,87 @@
# -*- coding: utf-8 -*-
"""05_build_crossref_report.py — 参校本对照报告(初对照)生成
输入:参校本对照_药目核对.json(03 脚本产物)+ _tmp_实字异文.json(04 脚本产物)
输出:02_加工数据/参校本对照_孙本-维基.md"""
import json, os, datetime
BASE = '/home/songyi/Documents/ai_agent_scraper_study/data/神农本草经'
D = json.load(open(os.path.join(BASE, '02_加工数据/参校本对照_药目核对.json'), encoding='utf-8'))
SUB = json.load(open(os.path.join(BASE, '02_加工数据/_tmp_实字异文.json'), encoding='utf-8'))
same = D['同文']
diff = D['异文条目']
only_sun = D['未对齐_仅孙本']
only_wk = D['未对齐_仅维基']
L = []
L.append('# 参校本对照 — 孙本(第一参照本·殆知阁) ⇄ 维基文库(第二参校本) 初步对照')
L.append('')
L.append('> 性质:**两参校本互校**,双方原文均未改动;差异只登记。本对照供实体书 OCR 底本核对时作为「第三源」线索定位——凡两参校本一致的异文、或两方各有主张的异文,都圈出来供底本定夺。')
L.append('> 规整规则(对照镜像,不是改字):① 繁→简单向转换(opencc t2s,仅对照视图)② 去括注(孙本多《御览》括注)③ 去句读(,。、;:)——均不动任何一方的原始文件。')
L.append('> 药名对齐用显式异体映射表(如 丹沙=丹砂、朴消=朴硝、慈石=磁石、茈胡=柴胡),映射SRﺎ只用于对照键。')
L.append('')
today = datetime.date.today().isoformat()
L.append('| 项 | 数 |')
L.append('|----|----|')
L.append('| 孙本药条(合并整理版口径) | 337 |')
L.append('| 维基药条 | 359 |')
L.append('| 对齐条目(名称可对) | %d |' % (len(same)+len(diff)))
L.append('| 两参校本文同 | %d |' % len(same))
L.append('| 对齐但文异(含体例差) | %d |' % len(diff))
L.append('| 剔除体例差后·实字异文条目 | **%d** |' % len(SUB := json.load(open(os.path.join(BASE, '02_加工数据/_tmp_实字异文.json'), encoding='utf-8'))))
L.append('| 未对齐·仅孙本 | %d |' % len(only_sun))
L.append('| 未对齐·仅维基 | %d |' % len(only_wk))
L.append('')
L.append('## 一、未对齐药名清单(四类成因)')
L.append('')
L.append('### 甲. 繁简异体(同一味药,用字不同——映射表已登记,属**版本体例差**,非内容差)')
L.append('')
L.append('如:丹沙/丹砂、朴消/朴硝、慈石/磁石、茈胡/柴胡、署豫/山芋系统、委萎/女萎……此层维基作繁体、孙本作简体+宋本用字,属繁简/异体书写差。')
L.append('')
L.append('### 未登记进映射表·成对残项(待人工归并):')
L.append('')
sun_left = [n for n in only_sun if n not in ('KT','下经','木','本','石','菌','青','黄','萆','蓬','虫','蓄')]
wk_left = only_wk
L.append('| 孙本侧 | 维基侧(可能对应) |')
L.append('|---------|-------------------|')
for s in sun_left:
L.append('| %s | (待人工归并) |' % s)
for w in wk_left[:20]:
L.append('| (待人工归并) | %s |' % w)
L.append('')
L.append('## 二、同文条目(两层规整后完全一致)[%d 条]' % len(same))
L.append('')
L.append('、'.join(same))
L.append('')
L.append('## 三、实字异文[粗筛 %d 条](样本)' % len(SUB))
L.append('')
L.append('> 注意:初筛自动剔除「治/有毒/无毒/小/微」等体例差;**繁简残留与形近字仍混入**,须人工定夺。每条列出「孙[原文]→维[原文]」。')
L.append('')
L.append('| 药名 | 差异(孙→维基) |')
L.append('|------|-----------------|')
for n, frags in list(SUB.items()):
cells = ';'.join('孙[%s]→维[%s]' % (f['孙'], f['维基']) for f in frags[:5])
L.append('| %s | %s |' % (n, cells.replace('|','\\|')))
L.append('')
L.append('## 四、全书结构差异(不在药条层面的差异)')
L.append('')
L.append('1. 孙本有《吴普》曰/《名医》曰/案:三重考据——维基文库全无')
L.append('2. 孙本有《御览》括注援引(《太平御览》引……)——维基无')
L.append('3. 维基有完整序录13行——孙本序录仅3段+目录行')
L.append('4. 维基三品分部按「玉石/草/木/果菜/米穀/蟲獸」——孙本按「卷一/二/三」')
L.append('5. 孙本卷三末附七情制使231种+《药对》五条——维基无')
L.append('6. 孙本药目数371>365、识别口径338——<strong>总计待底本核对后方能定</strong>')
L.append('')
L.append('## 五、下一步')
L.append('')
L.append('1. 未对齐药名人工归并清单→等底本OCR后定字')
L.append('2. 实字异文 228 条→等底本 OCR 后逐条定夺')
L.append('3. 序录 3 段 vs 13 行文本的取舍——以底本为准')
L.append('4. 孙本「KT」占位药条→底本核名')
L.append('')
md = '\n'.join(L)
md = md.replace('>>', '>')
open(os.path.join(BASE, '02_加工数据/参校本对照_孙本-维基.md'), 'w', encoding='utf-8').write(md)
print('已写 02_加工数据/参校本对照_孙本-维基.md,行数', md.count('\n')+1, 'md5:', __import__('hashlib').md5(md.encode()).hexdigest())