Files
health/神农本草经/05_脚本工具/03_compare_two_refs.py
T

139 lines
7.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# -*- 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))