Files
Igor20264 510f7e7adf
Python application / build (push) Waiting to run
v0.5.2
Что то сделал
2026-09-08 19:37:54 +03:00

171 lines
4.8 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.
"""Second pass: replace «Рисунок 1.1» / «табл. 2» with @Тип:id."""
from __future__ import annotations
import re
from .blocks import (
Block,
CaptionBlock,
EquationBlock,
ImageBlock,
InlineSpan,
ListBlock,
ListingBlock,
ParagraphBlock,
TableBlock,
)
from .captions import caption_unique_id
# Number like 1 / 1.1 / 2.3.4 — do NOT use [\d.]+ (eats trailing sentence period).
_NUM = r"(?P<num>\d+(?:\.\d+)*)"
_REF_PATTERNS = [
(
re.compile(
rf"(?P<full>(?:Рисунк(?:е|а|у|ом)?|Рисунок|Рис\.?)\s+{_NUM})",
re.IGNORECASE,
),
"figure",
),
(
re.compile(
rf"(?P<full>(?:Таблиц[аыеу]|табл\.?)\s+{_NUM})",
re.IGNORECASE,
),
"table",
),
(
re.compile(
rf"(?P<full>(?:Листинг(?:а|у|е|ом)?|лист\.?)\s+{_NUM})",
re.IGNORECASE,
),
"listing",
),
(
re.compile(
rf"(?P<full>(?:Формул[аыеу]|форм\.?)\s+{_NUM})",
re.IGNORECASE,
),
"equation",
),
]
_TYPE_LABEL = {
"figure": "Рисунок",
"table": "Таблица",
"listing": "Листинг",
"equation": "Формула",
}
def collect_number_maps(blocks: list[Block]) -> dict[str, dict[str, str]]:
"""kind → {number → unique_id}."""
maps: dict[str, dict[str, str]] = {
"figure": {},
"table": {},
"listing": {},
"equation": {},
}
for b in blocks:
if isinstance(b, CaptionBlock) and not b.is_continuation:
maps[b.kind][b.number] = b.unique_id or caption_unique_id(b.kind, b.number)
elif isinstance(b, ImageBlock) and b.caption_id:
num = _id_to_number(b.caption_id, "fig")
if num:
maps["figure"][num] = b.caption_id
elif isinstance(b, TableBlock) and b.caption_id:
num = _id_to_number(b.caption_id, "tbl")
if num:
maps["table"][num] = b.caption_id
elif isinstance(b, ListingBlock) and b.caption_id:
num = _id_to_number(b.caption_id, "lst")
if num:
maps["listing"][num] = b.caption_id
elif isinstance(b, EquationBlock) and b.number and b.unique_id:
maps["equation"][b.number] = b.unique_id
return maps
def _id_to_number(uid: str, prefix: str) -> str | None:
if not uid.startswith(prefix):
return None
rest = uid[len(prefix):]
if not rest:
return None
return rest.replace("_", ".")
def rewrite_text(text: str, maps: dict[str, dict[str, str]]) -> str:
"""Replace object references; leave bibliography [1] alone."""
if not text:
return text
def repl_factory(kind: str):
label = _TYPE_LABEL[kind]
num_map = maps.get(kind) or {}
def repl(m: re.Match) -> str:
num = m.group("num")
uid = num_map.get(num)
if not uid:
return m.group(0)
return f"@{label}:{uid}"
return repl
out = text
for pattern, kind in _REF_PATTERNS:
out = pattern.sub(repl_factory(kind), out)
return out
def _rewrite_paragraph_spans(para: ParagraphBlock, maps: dict[str, dict[str, str]]) -> None:
"""Rewrite refs even when Word split «Таблице 5.1» across runs."""
spans = para.spans
if not spans:
return
new_spans: list[InlineSpan] = []
i = 0
while i < len(spans):
s = spans[i]
if s.math or s.href:
new_spans.append(s)
i += 1
continue
j = i
chunk: list[InlineSpan] = []
while j < len(spans) and not spans[j].math and not spans[j].href:
chunk.append(spans[j])
j += 1
joined = "".join(p.text or "" for p in chunk)
rewritten = rewrite_text(joined, maps)
if rewritten == joined:
new_spans.extend(chunk)
else:
first = chunk[0]
same_fmt = all(
p.bold == first.bold and p.italic == first.italic and p.strike == first.strike
for p in chunk
)
new_spans.append(
InlineSpan(
text=rewritten,
bold=first.bold if same_fmt else False,
italic=first.italic if same_fmt else False,
strike=first.strike if same_fmt else False,
)
)
i = j
para.spans = new_spans
def apply_reference_pass(blocks: list[Block]) -> list[Block]:
maps = collect_number_maps(blocks)
for b in blocks:
if isinstance(b, ParagraphBlock):
_rewrite_paragraph_spans(b, maps)
elif isinstance(b, ListBlock):
b.items = [rewrite_text(item, maps) for item in b.items]
return blocks