139 lines
7.7 KiB
Python
139 lines
7.7 KiB
Python
# -*- 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))
|