feat: WordTemplateParser 章构成/占位符/样式名提取
This commit is contained in:
@@ -0,0 +1,11 @@
|
||||
"""Word 解析共享小工具(WordTemplateParser / RuleDocParser 复用)。"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
|
||||
def heading_level(style_name: str) -> int:
|
||||
"""从 Heading N 样式名解析大纲级别;非数字/无后缀兜底 1。"""
|
||||
try:
|
||||
return int(style_name.split()[-1])
|
||||
except (ValueError, IndexError):
|
||||
return 1
|
||||
@@ -0,0 +1,57 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
from pathlib import Path
|
||||
|
||||
from docx import Document
|
||||
from docx.oxml.ns import qn
|
||||
|
||||
from genesis.data_models import ChapterMarker, ParsedTemplate
|
||||
from genesis.parsers._word_common import heading_level
|
||||
|
||||
# 统一占位符正则:{{键名}} 或 {{键名:章节名}}(spec §3.2)
|
||||
PLACEHOLDER_RE = re.compile(r"\{\{([a-z][a-z0-9_]*)(?::([a-z][a-z0-9_]*))?\}\}")
|
||||
|
||||
|
||||
class WordTemplateParser:
|
||||
"""概要设计模板 docx 解析:章构成 / 占位符 / 样式名提取。"""
|
||||
|
||||
def parse(self, path: str | Path) -> ParsedTemplate:
|
||||
doc = Document(str(path))
|
||||
sections: list[ChapterMarker] = []
|
||||
placeholders: dict[str, str] = {}
|
||||
used_styles: set[str] = set()
|
||||
|
||||
# 文档命名样式(定义集合)
|
||||
defined = {s.name for s in doc.styles if s.name}
|
||||
|
||||
for para in doc.paragraphs:
|
||||
style_name = para.style.name if para.style else "Normal"
|
||||
used_styles.add(style_name)
|
||||
text = para.text
|
||||
|
||||
if style_name.startswith("Heading"):
|
||||
sections.append(ChapterMarker(
|
||||
type="heading", name=text, level=heading_level(style_name)
|
||||
))
|
||||
|
||||
for m in PLACEHOLDER_RE.finditer(text):
|
||||
if m.group(2):
|
||||
key = f"{m.group(1)}:{m.group(2)}"
|
||||
else:
|
||||
key = m.group(1)
|
||||
placeholders[key] = text
|
||||
sections.append(ChapterMarker(type="placeholder", name=key, level=0))
|
||||
|
||||
# 书签:遍历 body 中全部 bookmarkStart
|
||||
for bm in doc.element.body.iter(qn("w:bookmarkStart")):
|
||||
name = bm.get(qn("w:name"))
|
||||
if name:
|
||||
sections.append(ChapterMarker(type="bookmark", name=name, level=0))
|
||||
|
||||
return ParsedTemplate(
|
||||
file_name=Path(path).name,
|
||||
sections=sections,
|
||||
placeholders=placeholders,
|
||||
styles={"defined": sorted(defined), "used": sorted(used_styles)},
|
||||
)
|
||||
Reference in New Issue
Block a user