兼容性增强

资源数据补全
依赖更新
This commit is contained in:
sansen
2026-08-07 16:12:59 +08:00
parent a8d6e6f870
commit a850c72ab5
4 changed files with 275 additions and 33 deletions
+17
View File
@@ -30,6 +30,23 @@ dynasty_alias = {
"武周": "武周", "武周": "武周",
} }
# === 异体字/俗字归一表(OpenCC 未收录的字符) ===
# OpenCC 只处理标准繁简转换;古籍、碑刻、族谱中的异体字需在此补充。
# 匹配前对文本和 CSV 两侧做相同的归一化,保证一致。
VARIANT_MAP = {
'': '', '': '', # 年、岁的异体
'': '',
'': '', '': '', # 地支"卯"的异体
'': '', '': '', # 历的异体(万暦→万历)
}
# === 庙号别名 ===
# CSV 名号列与正文常用写法的差异
TEMPLE_ALIASES = {
"高帝": "高祖", # CSV 用"高帝",正文常用"高祖"
"始皇帝": "始皇", # CSV 用"始皇帝",正文常用"秦始皇"
}
# === 常见年号白名单(优先匹配,避免正则贪心误匹配) === # === 常见年号白名单(优先匹配,避免正则贪心误匹配) ===
KNOWN_ERAS = { KNOWN_ERAS = {
# 秦汉 # 秦汉
+250 -25
View File
@@ -3,14 +3,21 @@ import re
import pandas as pd import pandas as pd
from opencc import OpenCC from opencc import OpenCC
from era_data import dynasty_alias, KNOWN_ERAS from era_data import dynasty_alias, KNOWN_ERAS, VARIANT_MAP, TEMPLE_ALIASES
cc = OpenCC('t2s') cc = OpenCC('t2s')
def normalize_chars(text):
"""OpenCC 之外的异体字/俗字归一化。文本与 CSV 两侧必须走同一归一化,保证一致。"""
for variant, canonical in VARIANT_MAP.items():
text = text.replace(variant, canonical)
return text
# === 中文数字转阿拉伯数字 === # === 中文数字转阿拉伯数字 ===
def chinese_to_num(text): def chinese_to_num(text):
text = text.replace("", "三十").replace("", "四十") text = text.replace("", "三十").replace("", "四十").replace("", "")
if text in ["", "元年"]: if text in ["", "元年"]:
return 1 return 1
@@ -18,22 +25,36 @@ def chinese_to_num(text):
'': 0, '': 0, '': 0, '': 0, '': 0, '': 0,
'': 1, '': 2, '': 3, '': 4, '': 5, '': 6, '': 7, '': 8, '': 9, '': 1, '': 2, '': 3, '': 4, '': 5, '': 6, '': 7, '': 8, '': 9,
'': 10, '': 100, '': 1000, '': 10, '': 100, '': 1000,
'': 1, '': 2, '': 3, '': 4, '': 5, '': 6, '': 7, '': 8, '': 9, '': 10, '': 1, '': 2, '': 2, '': 3, '': 4, '': 5, '': 6, '': 6, '': 7, '': 8, '': 9, '': 10,
'': 20, '廿': 20, '': 30, '': 40, '': 20, '廿': 20, '': 30, '': 40,
} }
if text in chinese_numerals: if text in chinese_numerals:
return chinese_numerals[text] return chinese_numerals[text]
if '' in text:
parts = text.split('')
total = chinese_to_num(parts[0]) * 1000 if parts[0] else 1000
if len(parts) > 1 and parts[1]:
total += chinese_to_num(parts[1])
return total
if '' in text:
parts = text.split('')
total = chinese_to_num(parts[0]) * 100 if parts[0] else 100
if len(parts) > 1 and parts[1]:
total += chinese_to_num(parts[1])
return total
if '' in text: if '' in text:
parts = text.split('') parts = text.split('')
total = 0 total = 0
if parts[0] == '': if parts[0] == '':
total += 10 total += 10
else: else:
total += chinese_numerals.get(parts[0], 0) * 10 total += chinese_to_num(parts[0]) * 10
if len(parts) > 1 and parts[1]: if len(parts) > 1 and parts[1]:
total += chinese_numerals.get(parts[1], 0) total += chinese_to_num(parts[1])
return total return total
if '廿' in text or '' in text: if '廿' in text or '' in text:
@@ -68,14 +89,71 @@ def normalize_dynasty_name(dynasty):
# === 年号表 === # === 年号表 ===
def _cc(s):
"""CSV 单元格归一化:空值→'',其余走 OpenCC 繁转简 + 异体字归一"""
if pd.isna(s):
return ''
return normalize_chars(cc.convert(str(s)))
era_df = pd.read_csv("中国年号.csv") era_df = pd.read_csv("中国年号.csv")
era_df["年号"] = era_df["年号"].map(lambda x: cc.convert(str(x))) era_df["年号"] = era_df["年号"].map(_cc)
era_df["所属朝代"] = era_df["所属朝代"].map(lambda x: cc.convert(str(x))) era_df["所属朝代"] = era_df["所属朝代"].map(_cc)
era_df["名号"] = era_df["名号"].map(_cc)
def _safe_span(v):
"""CSV 使用年数列(可能为空或非数字)"""
try:
return int(float(v))
except (TypeError, ValueError):
return None
era_dict = {} era_dict = {}
# 年号使用年数:用于干支/年数结果的使用期校验(如庆元仅6年,期内无庚子)
era_span = {}
for _, row in era_df.iterrows(): for _, row in era_df.iterrows():
dynasty, era, start = row["所属朝代"], row["年号"], int(row["公元纪年"]) dynasty, era, start = row["所属朝代"], row["年号"], int(row["公元纪年"])
if not era:
continue
era_dict.setdefault(dynasty, {})[era] = start era_dict.setdefault(dynasty, {})[era] = start
span = _safe_span(row["使用年数"])
if span is not None:
era_span.setdefault(dynasty, {}).setdefault(era, span)
# 有效年号白名单 = 手工精选 ∪ CSV 年号(自动补全:白名单不应小于数据表)。
# 排除:民国(有专门匹配段)、带括号的年号(如"(后元)",防止与东汉"中元"等歧义)
_csv_eras = {
e for e in era_df["年号"]
if e and e != '民国' and '(' not in e and '' not in e and 2 <= len(e) <= 8
}
KNOWN_ERAS_ALL = KNOWN_ERAS | _csv_eras
# === 庙号表 ===
# 名号列(如"高宗""太宗")表示整个在位期,公元取该名号下最早的年份(即位首年)。
# "代宗(景帝)" 等带括号的写法拆成两种叫法都收录;只收祖/宗/帝/王/后/皇结尾(或帝开头)的名号,
# 排除"拖雷""孺子婴"等非庙号条目。
def _is_temple_name(name):
return len(name) >= 2 and (name.startswith('') or name.endswith(('', '', '', '', '', '')))
temple_dict = {}
# 庙号在位年数(该名号下各年号使用年数之和):用于名号+年数结果的使用期校验
temple_span = {}
for _, row in era_df.iterrows():
name, dynasty, start = row["名号"], row["所属朝代"], int(row["公元纪年"])
if not name or not dynasty:
continue
for part in re.split(r'[()()]', name):
part = part.strip()
if not part or not _is_temple_name(part):
continue
part = TEMPLE_ALIASES.get(part, part)
if not _is_temple_name(part):
continue
temple_dict.setdefault(dynasty, {}).setdefault(part, start)
span = _safe_span(row["使用年数"])
if span is not None:
d = temple_span.setdefault(dynasty, {})
d[part] = d.get(part, 0) + span
# === 干支纪年 === # === 干支纪年 ===
@@ -111,21 +189,24 @@ def arabic_to_chinese_year(num: int) -> str:
# === 古代年号正则 === # === 古代年号正则 ===
# 从 era_dict 构建朝代匹配组(按长度降序排列,优先匹配长朝代名如"北宋"而非"北" # 从 era_dict 构建朝代匹配组(按长度降序排列,优先匹配长朝代名如"北宋"而非"北"
# 额外添加常见但不在CSV中的朝代简称(如"汉" # 额外添加常见但不在CSV中的朝代简称(如"汉"
# 合并 temple_dict 的键:周/秦等年号列全空的朝代也必须有匹配能力
_extra_dynasty_names = ['', '', '', ''] _extra_dynasty_names = ['', '', '', '']
_dynasty_names = sorted( _dynasty_names = sorted(
list(era_dict.keys()) + [d for d in _extra_dynasty_names if d not in era_dict], list(era_dict.keys()) + list(temple_dict.keys())
+ [d for d in _extra_dynasty_names if d not in era_dict and d not in temple_dict],
key=len, reverse=True key=len, reverse=True
) )
_dynasty_alt = '|'.join(re.escape(d) for d in _dynasty_names) _dynasty_alt = '|'.join(re.escape(d) for d in _dynasty_names)
# 常见朝代前缀(大、皇等),用于匹配"大唐""大清"等 # 常见朝代前缀(大、皇等),用于匹配"大唐""大清"等
_dynasty_prefix = '大皇前后胡' _dynasty_prefix = '大皇前后胡'
# 非元年数字字符(排除元,避免歧义:建元元年中第一个元是年号的一部分) # 非元年数字字符(排除元,避免歧义:建元元年中第一个元是年号的一部分)
_year_digits = '〇零一二三四五六七八九十廿卄卅卌' # 含阿拉伯/全角数字("康熙20年""乾隆20年")与大写数字("道光贰拾年")。
_year_digits = '〇零一二三四五六七八九十廿卄卅卌' + '01234567890123456789' + '壹貳贰叁肆伍陸陆柒捌玖拾'
# 已知年号白名单见 era_data.py # 已知年号白名单见 era_data.py
# 预编译已知年号正则片段(按长度降序,优先匹配长年号如"太平兴国"而非"太平" # 预编译已知年号正则片段(按长度降序,优先匹配长年号如"太平兴国"而非"太平"
_known_era_alt = '|'.join(sorted(KNOWN_ERAS, key=len, reverse=True)) _known_era_alt = '|'.join(sorted(KNOWN_ERAS_ALL, key=len, reverse=True))
_known_era_group = r'(?P<era>' + _known_era_alt + r')' _known_era_group = r'(?P<era>' + _known_era_alt + r')'
_yd = '[' + _year_digits + ']' _yd = '[' + _year_digits + ']'
@@ -173,15 +254,18 @@ def extract_era_years(text):
# 去除标记用的方括号(用户标注用,非原文内容) # 去除标记用的方括号(用户标注用,非原文内容)
text = text.replace('[', '').replace(']', '') text = text.replace('[', '').replace(']', '')
original_text = text original_text = text
simplified_text = cc.convert(text) simplified_text = normalize_chars(cc.convert(text))
results = [] results = []
# 覆盖集:先匹配的段落占据位置,后续段落跳过重叠(防止同一文本被多段重复摘出)
covered = set()
# === 1. 民国 === # === 1. 民国 ===
minguo_pattern = re.compile(r'民[国國]\s*([〇零一二三四五六七八九十百廿卄卅卌元\d]+)\s*年') minguo_pattern = re.compile(r'民[国國]\s*([〇零一二三四五六七八九十百廿卄卅卌元\d-9壹貳贰叁肆伍陸陆柒捌玖拾]+)\s*年')
for m in minguo_pattern.finditer(simplified_text): for m in minguo_pattern.finditer(simplified_text):
year_text = m.group(1) year_text = m.group(1)
year_num = chinese_to_num(year_text) year_num = chinese_to_num(year_text)
start, end = m.start(), m.end() start, end = m.start(), m.end()
covered.update(range(start, end))
raw_fan = original_text[start:end] raw_fan = original_text[start:end]
results.append({ results.append({
"原文": raw_fan, "原文": raw_fan,
@@ -207,6 +291,7 @@ def extract_era_years(text):
year_in_era = ((gz_offset - base_gz) % 60) + 1 year_in_era = ((gz_offset - base_gz) % 60) + 1
gregorian = 1912 + year_in_era - 1 gregorian = 1912 + year_in_era - 1
start, end = m.start(), m.end() start, end = m.start(), m.end()
covered.update(range(start, end))
raw_fan = original_text[start:end] raw_fan = original_text[start:end]
results.append({ results.append({
"原文": raw_fan, "原文": raw_fan,
@@ -221,16 +306,82 @@ def extract_era_years(text):
"类型": "民国纪年(干支)", "类型": "民国纪年(干支)",
}) })
# === 2b. 年号+公元(如"清康熙公元一六八七年丁卯") ===
# 年号后直接给出公元年份:年数=公元-年号起始+1,与"年号+年数"公式自洽;
# 紧跟的干支用于校验年份一致性。置于公元段之前,合并结果优先、避免重复摘出。
_era_gongyuan = re.compile(
r'(?P<dynasty>(?:(?<![一-鿿])[' + _dynasty_prefix + r'](?:' + _dynasty_alt + r'))|(?:(?<![一-鿿])' + _dynasty_alt + r'))?'
+ r'(?P<era>' + _known_era_alt + r')'
+ r'公元\s*(?P<gy_year>[〇零○O一二三四五六七八九\d-]{3,4})\s*年?'
+ r'(?P<gy_ganzhi>' + _gz_pair + r')?'
)
for m in _era_gongyuan.finditer(simplified_text):
start, end = m.start(), m.end()
if any(pos in covered for pos in range(start, end)):
continue
era = cc.convert(m.group("era"))
year_num = chinese_to_num(m.group("gy_year"))
if not (1000 <= year_num <= 2100):
continue
dynasty = normalize_dynasty_name(m.group("dynasty") or "")
base = None
multi = []
if dynasty:
for d, eras in era_dict.items():
if dynasty in d or d in dynasty:
if era in eras:
base = eras[era]
dynasty = d
break
if base is None:
for d, eras in era_dict.items():
if era in eras:
multi.append((d, eras[era]))
if multi:
dynasty, base = multi[0]
if base is None:
continue
covered.update(range(start, end))
year_in_era = year_num - base + 1
ganzhi = m.group("gy_ganzhi")
result = {
"原文": original_text[start:end],
"原文(简体)": m.group(0),
"朝代": dynasty,
"年号": era,
"年数": year_in_era,
"公元": year_num,
"公元中文": f"{arabic_to_chinese_year(year_num)}",
"位置": {"起始": start, "结束": end},
"类型": "年号+公元",
}
if len(multi) > 1:
result["多候选"] = True
result["候选"] = [list(c) for c in multi]
# 公元超出年号使用期(如"康熙公元1950年")→ 标注,值保留
span = era_span.get(dynasty, {}).get(era)
if span is not None and year_num > base + span - 1:
result["超出使用期"] = True
# 紧跟的干支与公元年份不符(如"一六八九年丁卯",1689应为己巳)→ 标注
if ganzhi:
result["干支"] = ganzhi
if gregorian_to_ganzhi(year_num) != ganzhi:
result["干支不符"] = True
results.append(result)
# === 2. 公元(允许无"年"字)=== # === 2. 公元(允许无"年"字)===
gongyuan_pattern = re.compile( gongyuan_pattern = re.compile(
r'(公元)?\s*([〇零○O一二三四五六七八九\d]{3,4})\s*(?:.*?)?\s*(年)?' r'(公元)?\s*([〇零○O一二三四五六七八九\d-]{3,4})\s*(?:.*?)?\s*(年)?'
) )
for m in gongyuan_pattern.finditer(simplified_text): for m in gongyuan_pattern.finditer(simplified_text):
start, end = m.start(), m.end()
if any(pos in covered for pos in range(start, end)):
continue
year_text = m.group(2) year_text = m.group(2)
year_num = chinese_to_num(year_text) year_num = chinese_to_num(year_text)
if not (1000 <= year_num <= 2100): if not (1000 <= year_num <= 2100):
continue continue
start, end = m.start(), m.end() covered.update(range(start, end))
raw_fan = original_text[start:end] raw_fan = original_text[start:end]
era_type = "公元纪年(中华人民共和国)" if year_num >= 1949 else "公元纪年(近代/其他)" era_type = "公元纪年(中华人民共和国)" if year_num >= 1949 else "公元纪年(近代/其他)"
results.append({ results.append({
@@ -243,7 +394,6 @@ def extract_era_years(text):
}) })
# === 3. 干支纪年(如"清雍正乙巳十一月十二午时生")=== # === 3. 干支纪年(如"清雍正乙巳十一月十二午时生")===
covered = set()
def _process_ganzhi_match(m): def _process_ganzhi_match(m):
"""处理干支纪年匹配""" """处理干支纪年匹配"""
raw_dynasty = m.group("dynasty") if "dynasty" in m.groupdict() else "" raw_dynasty = m.group("dynasty") if "dynasty" in m.groupdict() else ""
@@ -255,6 +405,7 @@ def extract_era_years(text):
# 查找朝代和基准年 # 查找朝代和基准年
base = None base = None
multi = []
if dynasty: if dynasty:
for d, eras in era_dict.items(): for d, eras in era_dict.items():
if dynasty in d or d in dynasty: if dynasty in d or d in dynasty:
@@ -263,11 +414,12 @@ def extract_era_years(text):
dynasty = d dynasty = d
break break
if not base: if not base:
# 无朝代前缀:收集全部候选(如"大定"=北周581/金1161),取首个但标注歧义
for d, eras in era_dict.items(): for d, eras in era_dict.items():
if era in eras: if era in eras:
base = eras[era] multi.append((d, eras[era]))
dynasty = d if multi:
break dynasty, base = multi[0]
if not base: if not base:
return return
@@ -281,7 +433,7 @@ def extract_era_years(text):
return return
covered.update(range(start, end)) covered.update(range(start, end))
raw_fan = original_text[start:end] raw_fan = original_text[start:end]
results.append({ result = {
"原文": raw_fan, "原文": raw_fan,
"原文(简体)": m.group(0), "原文(简体)": m.group(0),
"朝代": dynasty, "朝代": dynasty,
@@ -292,13 +444,22 @@ def extract_era_years(text):
"公元中文": f"{arabic_to_chinese_year(gregorian)}", "公元中文": f"{arabic_to_chinese_year(gregorian)}",
"位置": {"起始": start, "结束": end}, "位置": {"起始": start, "结束": end},
"类型": "干支纪年", "类型": "干支纪年",
}) }
if len(multi) > 1:
result["多候选"] = True
result["候选"] = [list(c) for c in multi]
# 使用期校验:换算结果超出年号实际使用年数(如"庆元庚子"→1240,庆元仅11951200)。
# 值保留,仅标注,供人工判断(碑刻原数据常与年号实际期间不符)。
span = era_span.get(dynasty, {}).get(era)
if span is not None and gregorian > base + span - 1:
result["超出使用期"] = True
results.append(result)
# 模式A:有朝代前缀(如"清雍正乙巳") # 模式A:有朝代前缀(如"清雍正乙巳")
# 单字年号加前瞻(?![地支]),防止单字年号"丙"吞掉天干"丙午"中的"丙" # 单字年号加前瞻(?![地支]),防止单字年号"丙"吞掉天干"丙午"中的"丙"
_gz_era_group = r'(?P<era>' + '|'.join( _gz_era_group = r'(?P<era>' + '|'.join(
(re.escape(e) + (r'(?![子丑寅卯辰巳午未申酉戌亥])' if len(e) == 1 else '')) (re.escape(e) + (r'(?![子丑寅卯辰巳午未申酉戌亥])' if len(e) == 1 else ''))
for e in sorted(KNOWN_ERAS, key=len, reverse=True) for e in sorted(KNOWN_ERAS_ALL, key=len, reverse=True)
) + r')' ) + r')'
ganzhi_dynasty = re.compile( ganzhi_dynasty = re.compile(
r'(?P<dynasty>(?:(?<![一-鿿])[' + _dynasty_prefix + r'](?:' + _dynasty_alt + r'))|(?:(?<![一-鿿])' + _dynasty_alt + r'))' r'(?P<dynasty>(?:(?<![一-鿿])[' + _dynasty_prefix + r'](?:' + _dynasty_alt + r'))|(?:(?<![一-鿿])' + _dynasty_alt + r'))'
@@ -309,7 +470,7 @@ def extract_era_years(text):
_process_ganzhi_match(m) _process_ganzhi_match(m)
# 模式B:无朝代前缀(如"嘉庆癸亥"),年号≥2字符避免天干误匹配 # 模式B:无朝代前缀(如"嘉庆癸亥"),年号≥2字符避免天干误匹配
_long_era_names = [e for e in KNOWN_ERAS if len(e) >= 2] _long_era_names = [e for e in KNOWN_ERAS_ALL if len(e) >= 2]
_long_era_alt = '|'.join(sorted(_long_era_names, key=len, reverse=True)) _long_era_alt = '|'.join(sorted(_long_era_names, key=len, reverse=True))
ganzhi_no_dynasty = re.compile( ganzhi_no_dynasty = re.compile(
r'(?P<dynasty>)' r'(?P<dynasty>)'
@@ -319,6 +480,49 @@ def extract_era_years(text):
for m in ganzhi_no_dynasty.finditer(simplified_text): for m in ganzhi_no_dynasty.finditer(simplified_text):
_process_ganzhi_match(m) _process_ganzhi_match(m)
# === 3b. 庙号纪年(如"宋高宗""清圣祖",指整个在位期,公元=即位首年)===
# 庙号必须带朝代前缀("高宗"在唐/宋/清均有,单独出现有歧义)
_temple_names = sorted({t for d in temple_dict for t in temple_dict[d]}, key=len, reverse=True)
_temple_alt = '|'.join(re.escape(t) for t in _temple_names)
_temple_pattern = re.compile(
r'(?P<dynasty>(?:(?<![一-鿿])[' + _dynasty_prefix + r'](?:' + _dynasty_alt + r'))|(?:(?<![一-鿿])' + _dynasty_alt + r'))'
+ r'(?P<temple>' + _temple_alt + r')'
# 后面紧跟"X年/元年"时不按庙号匹配,交给古代纪年按年号解析(如"元泰定三年")
+ r'(?!(?:' + _yd + r'+年|元年))'
)
for m in _temple_pattern.finditer(simplified_text):
start, end = m.start(), m.end()
if any(pos in covered for pos in range(start, end)):
continue
dynasty = normalize_dynasty_name(m.group("dynasty") or "")
temple = m.group("temple")
base = None
if dynasty:
# 先精确匹配朝代,再模糊匹配(如"宋"→"南宋"
for d in temple_dict:
if d == dynasty and temple in temple_dict[d]:
dynasty, base = d, temple_dict[d][temple]
break
if base is None:
for d in temple_dict:
if (dynasty in d or d in dynasty) and temple in temple_dict[d]:
dynasty, base = d, temple_dict[d][temple]
break
if base is None:
continue
covered.update(range(start, end))
raw_fan = original_text[start:end]
results.append({
"原文": raw_fan,
"原文(简体)": m.group(0),
"朝代": dynasty,
"庙号": temple,
"公元": base,
"公元中文": f"{arabic_to_chinese_year(base)}",
"位置": {"起始": start, "结束": end},
"类型": "庙号纪年",
})
# === 4. 古代年号 === # === 4. 古代年号 ===
def _process_era_match(m, year_override=None): def _process_era_match(m, year_override=None):
@@ -336,6 +540,7 @@ def extract_era_years(text):
year_text = year_override if year_override is not None else m.group("year") year_text = year_override if year_override is not None else m.group("year")
year_num = chinese_to_num(year_text) year_num = chinese_to_num(year_text)
base = None base = None
multi = []
if dynasty: if dynasty:
for d, eras in era_dict.items(): for d, eras in era_dict.items():
@@ -345,6 +550,7 @@ def extract_era_years(text):
dynasty = d dynasty = d
break break
else: else:
# 无朝代前缀:收集全部候选(如"建元"=西汉-140/东晋343/南齐479),取首个但标注歧义
candidates = [] candidates = []
for d, eras in era_dict.items(): for d, eras in era_dict.items():
if era in eras: if era in eras:
@@ -353,13 +559,22 @@ def extract_era_years(text):
dynasty, base = candidates[0] dynasty, base = candidates[0]
elif len(candidates) > 1: elif len(candidates) > 1:
dynasty, base = candidates[0] dynasty, base = candidates[0]
multi = candidates
if base is None:
# 名号+年数兜底(如"汉惠帝三年"→即位首年-194 + 3 - 1,指皇帝在位第N年)
if dynasty:
for d, temples in temple_dict.items():
if (dynasty in d or d in dynasty) and era in temples:
base = temples[era]
dynasty = d
break
start, end = m.start(), m.end() start, end = m.start(), m.end()
raw_fan = original_text[start:end] raw_fan = original_text[start:end]
covered.update(range(start, end)) covered.update(range(start, end))
if base: if base:
gregorian = base + year_num - 1 gregorian = base + year_num - 1
results.append({ result = {
"原文": raw_fan, "原文": raw_fan,
"原文(简体)": m.group(0), "原文(简体)": m.group(0),
"朝代": dynasty, "朝代": dynasty,
@@ -369,7 +584,17 @@ def extract_era_years(text):
"公元中文": f"{arabic_to_chinese_year(gregorian)}", "公元中文": f"{arabic_to_chinese_year(gregorian)}",
"位置": {"起始": start, "结束": end}, "位置": {"起始": start, "结束": end},
"类型": "古代纪年", "类型": "古代纪年",
}) }
if len(multi) > 1:
result["多候选"] = True
result["候选"] = [list(c) for c in multi]
# 使用期校验:年数结果超出年号使用期(或名号在位年数)时标注,值保留
span = era_span.get(dynasty, {}).get(era)
if span is None:
span = temple_span.get(dynasty, {}).get(era)
if span is not None and gregorian > base + span - 1:
result["超出使用期"] = True
results.append(result)
else: else:
results.append({ results.append({
"原文": raw_fan, "原文": raw_fan,
+6 -6
View File
@@ -1,6 +1,6 @@
pytest~=9.1.1 uvicorn~=0.33.0
uvicorn~=0.50.0 fastapi~=0.124.4
fastapi~=0.139.0 loguru~=0.7.2
loguru~=0.7.3 pandas~=1.5.3
pandas~=2.3.3 opencc-python-reimplemented~=0.1.7
OpenCC~=1.4.1 python-multipart~=0.0.20
+2 -2
View File
@@ -554,8 +554,8 @@
中国,天命,太祖,爱新觉罗努尔哈赤,11616,11627,1616,正月,丙辰,11, 中国,天命,太祖,爱新觉罗努尔哈赤,11616,11627,1616,正月,丙辰,11,
中国,天聪,太宗,爱新觉罗皇太极,11627,11637,1627,正月,丁卯,10, 中国,天聪,太宗,爱新觉罗皇太极,11627,11637,1627,正月,丁卯,10,
中国,崇德,太宗,爱新觉罗皇太极,11636,11644,1636,四月,丙子,8, 中国,崇德,太宗,爱新觉罗皇太极,11636,11644,1636,四月,丙子,8,
中国,顺治,,爱新觉罗福临,11644,11662,1644,正月,甲申,18, 中国,顺治,,爱新觉罗福临,11644,11662,1644,正月,甲申,18,
中国,康熙,,爱新觉罗玄烨,11662,11723,1662,正月,壬寅,61, 中国,康熙,,爱新觉罗玄烨,11662,11723,1662,正月,壬寅,61,
中国,雍正,世宗,爱新觉罗胤禛,11723,11736,1723,正月,癸卯,13, 中国,雍正,世宗,爱新觉罗胤禛,11723,11736,1723,正月,癸卯,13,
中国,乾隆,高宗,爱新觉罗弘历,11736,11796,1736,正月,丙辰,60, 中国,乾隆,高宗,爱新觉罗弘历,11736,11796,1736,正月,丙辰,60,
中国,嘉庆,仁宗,爱新觉罗颙琰,11796,11821,1796,正月,丙辰,25, 中国,嘉庆,仁宗,爱新觉罗颙琰,11796,11821,1796,正月,丙辰,25,
1 国别 年号 名号 姓名 起HE 止HE 公元纪年 改元月份 元年干支 使用年数 所属朝代
554 中国 天命 太祖 爱新觉罗努尔哈赤 11616 11627 1616 正月 丙辰 11
555 中国 天聪 太宗 爱新觉罗皇太极 11627 11637 1627 正月 丁卯 10
556 中国 崇德 太宗 爱新觉罗皇太极 11636 11644 1636 四月 丙子 8
557 中国 顺治 世宗 世祖 爱新觉罗福临 11644 11662 1644 正月 甲申 18
558 中国 康熙 圣宗 圣祖 爱新觉罗玄烨 11662 11723 1662 正月 壬寅 61
559 中国 雍正 世宗 爱新觉罗胤禛 11723 11736 1723 正月 癸卯 13
560 中国 乾隆 高宗 爱新觉罗弘历 11736 11796 1736 正月 丙辰 60
561 中国 嘉庆 仁宗 爱新觉罗颙琰 11796 11821 1796 正月 丙辰 25