|
|
@@ -142,6 +142,12 @@ def parse_docx(filepath: str) -> dict | None:
|
|
|
if current_text:
|
|
|
sections[current_section] = '\n'.join(current_text).strip()
|
|
|
|
|
|
+ # ============================================
|
|
|
+ # 凡例/纲要特殊处理:按编号拆分(一、二、三... 或 1. 2. 3.)
|
|
|
+ # ============================================
|
|
|
+ if parent_dir in ("凡例", "纲要") and "正文" in sections:
|
|
|
+ sections = split_numbered_content(sections["正文"])
|
|
|
+
|
|
|
if len(sections) == 0:
|
|
|
return None
|
|
|
|
|
|
@@ -163,6 +169,73 @@ def parse_docx(filepath: str) -> dict | None:
|
|
|
}
|
|
|
|
|
|
|
|
|
+def split_numbered_content(text: str) -> OrderedDict:
|
|
|
+ """
|
|
|
+ 凡例/纲要类内容按编号拆分为独立 section。
|
|
|
+ 匹配模式:
|
|
|
+ - 一、二、三、... 十四、
|
|
|
+ - (一)(二)...
|
|
|
+ - 1. 2. 3. 或 1)2)3)
|
|
|
+ """
|
|
|
+ # 中文数字
|
|
|
+ cn_nums = "一二三四五六七八九十"
|
|
|
+ patterns = [
|
|
|
+ # ^一、或 \n一、 开头
|
|
|
+ re.compile(r'(?:^|\n)([' + cn_nums + r']{1,2})[、,,]'),
|
|
|
+ # (一)开头
|
|
|
+ re.compile(r'(?:^|\n)(([' + cn_nums + r']{1,2}))'),
|
|
|
+ # 数字编号
|
|
|
+ re.compile(r'(?:^|\n)(\d{1,2})[\.\))]'),
|
|
|
+ ]
|
|
|
+
|
|
|
+ # 用第一个模式尝试
|
|
|
+ result = OrderedDict()
|
|
|
+ pattern = patterns[0]
|
|
|
+ matches = list(pattern.finditer(text))
|
|
|
+
|
|
|
+ if len(matches) < 2:
|
|
|
+ # 尝试第二个模式
|
|
|
+ pattern = patterns[1]
|
|
|
+ matches = list(pattern.finditer(text))
|
|
|
+
|
|
|
+ if len(matches) < 2:
|
|
|
+ # 尝试第三个模式
|
|
|
+ pattern = patterns[2]
|
|
|
+ matches = list(pattern.finditer(text))
|
|
|
+
|
|
|
+ if len(matches) < 2:
|
|
|
+ # 确实没有编号结构,保留原样但限制长度
|
|
|
+ if len(text) > 3000:
|
|
|
+ # 按段落粗略切分
|
|
|
+ paras = [p.strip() for p in text.split('\n') if p.strip()]
|
|
|
+ buf = ""
|
|
|
+ idx = 0
|
|
|
+ for p in paras:
|
|
|
+ if len(buf) + len(p) > 2000 and buf:
|
|
|
+ result[f"第{idx + 1}段"] = buf
|
|
|
+ idx += 1
|
|
|
+ buf = p
|
|
|
+ else:
|
|
|
+ buf += ("\n" if buf else "") + p
|
|
|
+ if buf:
|
|
|
+ result[f"第{idx + 1}段"] = buf
|
|
|
+ return result if result else OrderedDict([("正文", text)])
|
|
|
+ return OrderedDict([("正文", text)])
|
|
|
+
|
|
|
+ # 按编号切分
|
|
|
+ for i, match in enumerate(matches):
|
|
|
+ start = match.start()
|
|
|
+ end = matches[i + 1].start() if i + 1 < len(matches) else len(text)
|
|
|
+ content = text[start:end].strip()
|
|
|
+ # 编号字符串(去除换行和括号)
|
|
|
+ raw_num = match.group(0).lstrip('\n').strip()
|
|
|
+ section_name = f"凡例-{raw_num}"
|
|
|
+ if len(content) > 50:
|
|
|
+ result[section_name] = content
|
|
|
+
|
|
|
+ return result if result else OrderedDict([("正文", text)])
|
|
|
+
|
|
|
+
|
|
|
def is_pinyin_line(text: str) -> bool:
|
|
|
alpha_count = sum(1 for c in text if c.isascii() and c.isalpha())
|
|
|
return alpha_count > len(text) * 0.3 and len(text) > 3 and len(text) < 200
|