# -*- 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))