Files
md2word/transit/references.py
zzy 4e39a4f2ac feat(transit): 添加正文引用标记到书签超链接功能
- 新增 CITE_PATTERN 正则表达式匹配 [N] 引用格式
- 添加 base_dir 参数支持相对图片路径解析
- 实现书签创建和超链接替换功能
- 添加 link_body_citations 函数处理正文引用链接
- 在参考文献段落中添加书签标识
- 支持将 [N] 引用替换为指向参考文献的超链接
2026-05-10 15:07:20 +08:00

119 lines
3.3 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
GB 7714 《文后参考文献著录规则》顺序编码制 — 参考文献解析与格式化。
将 Markdown 中 ``[N] ... [TYPE] ...`` 格式的参考文献逐条解析,
按文献类型(书 M、期刊 J、会议 C、学位论文 D、标准 S、电子资源 EB/OL 等)
重新编排为符合 GB 7714 规范的格式,并输出为独立段落。
"""
import re
from typing import Optional
# 单行匹配: [N] 开头
_RE_LINE = re.compile(r"^\[(\d+)\]\s*(.*)$")
# 文献类型标记: [M] [J] [C] [D] [S] [EB/OL] [P] [N]
_RE_TYPE = re.compile(r"\[(\w+(?:/\w+)?)\]")
# GB 7714 中各文献类型的标准格式模板(仅用于说明,实际格式化直接拼接)
TYPE_LABELS: dict[str, str] = {
"M": "专著",
"J": "期刊文章",
"C": "会议论文",
"D": "学位论文",
"S": "标准",
"EB/OL": "电子资源",
"P": "专利",
"N": "报纸文章",
}
def parse_reference_line(line: str) -> Optional[dict]:
"""解析单行参考文献,提取序号、作者+标题、文献类型、来源信息。
期望格式::
[N] Authors. Title[TYPE]. Source info.
"""
line = line.strip()
m = _RE_LINE.match(line)
if not m:
return None
number = int(m.group(1))
rest = m.group(2).strip()
# 定位文献类型标记 [TYPE]
tm = _RE_TYPE.search(rest)
if not tm:
return None
before_type = rest[: tm.start()].strip().rstrip(".")
doc_type = tm.group(1)
after_type = rest[tm.end() :].strip().lstrip(".").strip()
return {
"number": number,
"before_type": before_type, # "Authors. Title"
"doc_type": doc_type, # "M", "J", "EB/OL", …
"after_type": after_type, # 来源信息
}
def _normalize_period(text: str) -> str:
"""确保文本以英文句点结尾GB 7714 要求)。"""
text = text.rstrip()
if text and not text.endswith("."):
text += "."
return text
def format_gb7714(ref: dict) -> str:
"""按 GB 7714 重新编排一条参考文献(不含序号前缀,由 Word 样式自动编号)。
格式::
Authors. Title[TYPE]. Source.
"""
bt = ref["before_type"]
dt = ref["doc_type"]
at = ref["after_type"]
formatted = f"{bt}[{dt}]. {at}"
return _normalize_period(formatted)
def references_to_paragraphs(
ref_text: str,
ref_style: str = "列出段落1",
) -> list[dict]:
"""将参考文献原始文本转换为格式化段落列表。
返回的每个元素::
{"text": str, "level": 0, "style": ref_style}
每条参考文献为一个独立段落。
"""
if not ref_text or ref_text == "<None>":
return [{"text": "<None>", "level": 0, "style": ref_style}]
lines = [l.strip() for l in ref_text.strip().split("\n") if l.strip()]
paragraphs: list[dict] = []
for line in lines:
ref = parse_reference_line(line)
if ref:
formatted = format_gb7714(ref)
ref_id = ref["number"]
else:
# 无法解析时,至少去掉 [N] 前缀
fallback = re.sub(r"^\[\d+\]\s*", "", line)
formatted = _normalize_period(fallback)
ref_id = None
paragraphs.append(
{"text": formatted, "level": 0, "style": ref_style, "ref_id": ref_id}
)
return paragraphs