1a5b35eb54
Python application / build (push) Has been cancelled
- add Local Render Mermaid - add page-starе для указания смещения страниц - add Гиперссылки в документе на списки литературы
63 lines
1.6 KiB
Python
63 lines
1.6 KiB
Python
"""Bibliography parsing helpers (no docx dependency) and optional renderable."""
|
||
|
||
from __future__ import annotations
|
||
|
||
import re
|
||
from dataclasses import dataclass
|
||
|
||
|
||
BIBLIO_LINE_RE = re.compile(
|
||
r"^\[(\d+(?:\.\d+)?)\]:\s*(.+)$"
|
||
)
|
||
CITE_RE = re.compile(
|
||
r"\[(\d+(?:\.\d+)?(?:\s*,\s*\d+(?:\.\d+)?)*)"
|
||
r"(?:\s*,\s*[cс]\.\s*[\d\-–]+)?"
|
||
r"\]"
|
||
)
|
||
|
||
|
||
def biblio_bookmark_name(key: str) -> str:
|
||
"""Word bookmark name for bibliography key (dots → underscores)."""
|
||
return "biblio_" + str(key).replace(".", "_")
|
||
|
||
|
||
@dataclass
|
||
class BiblioEntry:
|
||
key: str
|
||
text: str
|
||
year: int | None = None
|
||
|
||
|
||
def extract_year(text: str) -> int | None:
|
||
years = re.findall(r"(?:^|[^\d])((?:19|20)\d{2})(?:[^\d]|$)", text)
|
||
if not years:
|
||
return None
|
||
return max(int(y) for y in years)
|
||
|
||
|
||
def parse_biblio_block(lines: list[str]) -> list[BiblioEntry]:
|
||
entries = []
|
||
for line in lines:
|
||
m = BIBLIO_LINE_RE.match(line.strip())
|
||
if m:
|
||
key, text = m.group(1), m.group(2).strip()
|
||
entries.append(BiblioEntry(key=key, text=text, year=extract_year(text)))
|
||
return entries
|
||
|
||
|
||
def find_citations(text: str) -> list[str]:
|
||
seen: list[str] = []
|
||
for m in CITE_RE.finditer(text):
|
||
inner = m.group(1)
|
||
for part in re.split(r"\s*,\s*", inner):
|
||
part = part.strip()
|
||
if part and part not in seen:
|
||
seen.append(part)
|
||
return seen
|
||
|
||
|
||
def Bibliography(*args, **kwargs):
|
||
"""Lazy wrapper to avoid importing docx/freetype at checker import time."""
|
||
from .bibliography_renderable import Bibliography as _Bibliography
|
||
return _Bibliography(*args, **kwargs)
|