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

150 lines
3.7 KiB
Python

"""Best-effort OMML → readable LaTeX-like string for $$ / $ fences."""
from __future__ import annotations
_OMML_NS = "http://schemas.openxmlformats.org/officeDocument/2006/math"
def _local(tag: str) -> str:
if "}" in tag:
return tag.rsplit("}", 1)[-1]
return tag
def omml_to_latex(element) -> str:
"""Flatten OMML tree to a readable formula string (not perfect LaTeX)."""
if element is None:
return ""
parts: list[str] = []
_walk(element, parts)
text = "".join(parts)
text = " ".join(text.split())
return text.strip()
def _walk(node, parts: list[str]) -> None:
tag = _local(node.tag)
if tag == "t":
parts.append(node.text or "")
return
if tag == "f": # fraction
num = _child(node, "num")
den = _child(node, "den")
parts.append(r"\frac{")
if num is not None:
_walk(num, parts)
parts.append("}{")
if den is not None:
_walk(den, parts)
parts.append("}")
return
if tag == "sSup":
base = _child(node, "e")
sup = _child(node, "sup")
if base is not None:
_walk(base, parts)
parts.append("^{")
if sup is not None:
_walk(sup, parts)
parts.append("}")
return
if tag == "sSub":
base = _child(node, "e")
sub = _child(node, "sub")
if base is not None:
_walk(base, parts)
parts.append("_{")
if sub is not None:
_walk(sub, parts)
parts.append("}")
return
if tag == "sSubSup":
base = _child(node, "e")
sub = _child(node, "sub")
sup = _child(node, "sup")
if base is not None:
_walk(base, parts)
parts.append("_{")
if sub is not None:
_walk(sub, parts)
parts.append("}^{")
if sup is not None:
_walk(sup, parts)
parts.append("}")
return
if tag == "rad":
deg = _child(node, "deg")
e = _child(node, "e")
if deg is not None and "".join(deg.itertext()).strip():
parts.append(r"\sqrt[")
_walk(deg, parts)
parts.append("]{")
else:
parts.append(r"\sqrt{")
if e is not None:
_walk(e, parts)
parts.append("}")
return
if tag == "nary":
for child in node:
_walk(child, parts)
return
if tag in ("oMath", "oMathPara", "e", "num", "den", "sup", "sub", "deg",
"fPr", "ctrlPr", "rPr", "sSupPr", "sSubPr", "sSubSupPr", "radPr",
"naryPr", "dPr", "boxPr", "argSz"):
for child in node:
_walk(child, parts)
return
if tag == "r":
for child in node:
_walk(child, parts)
return
if tag == "d": # delimiter
parts.append("(")
for child in node:
if _local(child.tag) != "dPr":
_walk(child, parts)
parts.append(")")
return
if tag in ("pPr", "rFonts", "sz", "szCs", "color", "jc"):
return
for child in node:
_walk(child, parts)
if node.tail:
parts.append(node.tail)
def _child(node, local_name: str):
for child in node:
if _local(child.tag) == local_name:
return child
return None
def find_omml(paragraph_element) -> list:
"""Return all m:oMath / m:oMathPara elements under a paragraph."""
if paragraph_element is None:
return []
found = []
for el in paragraph_element.iter():
tag = _local(el.tag)
if tag in ("oMath", "oMathPara"):
found.append(el)
return found
def paragraph_has_omml(paragraph_element) -> bool:
return bool(find_omml(paragraph_element))