From dc399ec8edc0d64e4f4fb525c460791588ae361d Mon Sep 17 00:00:00 2001 From: sansen Date: Mon, 21 Sep 2026 14:57:31 +0800 Subject: [PATCH] =?UTF-8?q?=E8=AF=AF=E5=8C=B9=E9=85=8D=E6=B2=BB=E7=90=86?= =?UTF-8?q?=EF=BC=9A=E8=A3=B8=E5=B9=B4=E4=BB=BD=E6=94=B9=E7=99=BD=E5=90=8D?= =?UTF-8?q?=E5=8D=95=E3=80=81=E5=85=AC=E5=85=83=E6=95=B0=E5=AD=97=E5=8A=A0?= =?UTF-8?q?=E8=BE=B9=E7=95=8C=E3=80=81=E5=B9=B4=E6=95=B0=E4=B8=8A=E7=95=8C?= =?UTF-8?q?=E4=B8=8E=E6=B0=91=E5=9B=BD=E7=AA=97=E5=8F=A3=E6=A0=A1=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- parser.py | 51 +++++++++++++++++++++++++++++++++------------------ 1 file changed, 33 insertions(+), 18 deletions(-) diff --git a/parser.py b/parser.py index 12513d6..2285038 100644 --- a/parser.py +++ b/parser.py @@ -317,19 +317,19 @@ _known_era_alt = '|'.join(sorted(KNOWN_ERAS_ALL, key=len, reverse=True)) _known_era_group = r'(?P' + _known_era_alt + r')' _yd = '[' + _year_digits + ']' # 年份后缀:"年"字可省(碑谱/契约常见:"民国二十六""万历三十六",也支持后接干支 -# "光绪二十六庚子")。省"年"时靠负向前瞻 _year_guard 兜住误匹配: -# 数字后面若还是数字字符或 万/亿,说明它只是一个更长数量的一部分("万历二十万"),不认。 -# 该 guard 同时挡住正则回溯:若整体匹配失败而回退到更短的数字串,其下一个字符必然仍是 -# 数字字符,guard 同样不通过(Python 3.10 没有原子组/占有量词,只能这样写)。 -# 裸年份(后面既无"年"、也无干支)后面若跟这些字,说明数字不是年数,一律不认: -# 月/日/号 → 月份日期("康熙六月""民国七月十二") -# 子/女/弟/兄/孙/婿/郎 → 亲属排行("张景福三子") -# 都/图/里 → 地名/行政区("永明五十二都") -# 岁/人/名/位/个/两/斤/石/亩/间/匹/只/件/张/条/次/层/种/倍/余/多 → 量词/约数 -# 注意不含天干(甲乙丙丁…):紧跟干支的写法("光绪二十六庚子")不受影响。 -_bare_year_forbid = '月日号子女子弟兄孙婿郎都图里岁人名位个两次条张匹只件斤两石亩间层种倍余多' -_year_guard = r'(?![' + _year_digits + r'万亿' + _bare_year_forbid + r'])' -_year_suffix = _year_guard + r'(?:年)?' +# "光绪二十六庚子")。省"年"时用**白名单前瞻**兜住误匹配——数字后只有跟下列内容才算年份: +# ① 族谱常用动词:生卒殁殇死终葬娶适嫁亡逝享寿嗣立 +# ② 标点/括号/引号/空白/行尾:,。、;:,.;:!?!?""''()()[]【】{}《》<> 及 \s、$ +# ③ 天干(甲乙丙丁戊己庚辛壬癸):后面就是干支,由各段自行并入并校验 +# 于是这些都不再当年份:康熙六月(月)、万历三大征(大)、康熙四十二卷(卷/42卷)、 +# 张景福三子(子/排行)、永明五十二都(都/地名)、万历二十万(万)、光绪二十六日(日)、 +# 康熙二十天(天/20天)。白名单也天然挡住正则回溯:回退到更短数字串时其后仍是数字,不在表内。 +_bare_year_after = ( + '生卒殁殤殇死终終葬娶适適嫁亡逝享寿壽嗣立' + + ',。、;:,.;:!?!?“”"\'‘’()()[]【】{}《》<>' + + _tiangan +) +_year_suffix = r'(?:年|(?=[' + re.escape(_bare_year_after) + r'\s]|$))' def _build_pattern(with_dynasty=True): """构建年号正则:已知年号优先 + 通用兜底(仅限有朝代前缀时)""" @@ -377,8 +377,12 @@ _patterns_dynasty = _build_pattern(with_dynasty=True) # 置于公元段之前(见 extract_era_years),避免对照年份被单独摘出成公元纪年。 _dynasty_opt = (r'(?P(?:(?(?:(?' + _known_era_alt + r')' - + r'(?:公元|西元|公历)\s*(?P[〇零○O一二三四五六七八九\d0-9]{3,4})\s*年?' + + r'(?:公元|西元|公历)\s*(?P' + _gz_gy_year + r')\s*年?' + r'(?P' + _gz_pair + r')?' ) for m in _era_gongyuan.finditer(simplified_text): @@ -657,7 +668,7 @@ def extract_era_years(text): # === 2. 公元(允许无"年"字)=== gongyuan_pattern = re.compile( - r'(?:公元|西元|公历)?\s*([〇零○O一二三四五六七八九\d0-9]{3,4})\s*(?:(.*?))?\s*(年)?' + r'(?:公元|西元|公历)?\s*(' + _gz_gy_year + r')\s*(?:(.*?))?\s*(年)?' ) for m in gongyuan_pattern.finditer(simplified_text): start, end = m.start(), m.end() @@ -837,6 +848,10 @@ def extract_era_years(text): return year_text = year_override if year_override is not None else m.group("year") year_num = chinese_to_num(year_text) + # 年数上界:年号纪年不可能出现"洪武146356"这类(那是被当年份的数字 ID/编号), + # 年数 > 999 一律不认——否则会算出 147723 这种荒诞公元 + if not (1 <= year_num <= 999): + return base = None multi = []