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

86 lines
2.9 KiB
Python
Raw 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.
"""Parse ГОСТ-style captions: Рисунок / Таблица / Листинг (+ продолжения)."""
from __future__ import annotations
import re
from dataclasses import dataclass
from md2gost.word_fix import parse_caption_text
_FIGURE_RE = re.compile(
r"^(?:Рисунок|Рис\.?)\s+(?P<number>[\d.]+)\s*(?:[—–\-]\s*(?P<title>.+))?$",
re.IGNORECASE,
)
_TABLE_FULL_RE = re.compile(
r"^(?:Продолжение\s+)?"
r"(?P<kind>Таблица|Таблицы|Листинг|Листинга)\s+"
r"(?P<number>[\d.]+)"
r"(?:\s*[—–\-]\s*(?P<title>.+))?$",
re.IGNORECASE,
)
_CONTINUATION_RE = re.compile(r"^Продолжение\s+(?:Таблицы|Листинга)\b", re.IGNORECASE)
@dataclass
class ParsedCaption:
kind: str # figure | table | listing
number: str
text: str | None = None
is_continuation: bool = False
def caption_unique_id(kind: str, number: str) -> str:
"""Stable id from display number: 1.1 → fig1_1 / tbl1_1 / lst1_1."""
safe = str(number).replace(".", "_")
prefix = {"figure": "fig", "table": "tbl", "listing": "lst"}.get(kind, "obj")
return f"{prefix}{safe}"
def parse_any_caption(text: str) -> ParsedCaption | None:
"""Parse figure / table / listing captions (including «Продолжение…»)."""
raw = (text or "").replace("\r", "").replace("\x07", "").strip()
if not raw:
return None
first = raw.split("\n", 1)[0].strip()
m = _FIGURE_RE.match(first)
if m:
title = (m.group("title") or "").strip().rstrip(".") or None
return ParsedCaption(kind="figure", number=m.group("number"), text=title)
info = parse_caption_text(first)
if info is not None:
title = None
m2 = _TABLE_FULL_RE.match(first)
if m2 and m2.group("title"):
title = m2.group("title").strip().rstrip(".") or None
else:
# Strip leading «Таблица N — » / «Продолжение…» for leftover title
rest = _TABLE_FULL_RE.sub("", first).strip()
if rest.startswith(("", "", "-")):
rest = rest[1:].strip()
title = rest.rstrip(".") or None if rest else None
return ParsedCaption(
kind=info.kind,
number=info.number,
text=title,
is_continuation=info.is_continuation,
)
m3 = _TABLE_FULL_RE.match(first)
if m3:
kind_raw = m3.group("kind").lower()
if kind_raw.startswith("табл"):
kind = "table"
elif kind_raw.startswith("лист"):
kind = "listing"
else:
return None
return ParsedCaption(
kind=kind,
number=m3.group("number"),
text=(m3.group("title") or "").strip().rstrip(".") or None,
is_continuation=bool(_CONTINUATION_RE.match(first)),
)
return None