@@ -0,0 +1,78 @@
|
||||
"""Extract visible text from OOXML runs/paragraphs (incl. w:noBreakHyphen)."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from docx.oxml.ns import qn
|
||||
|
||||
|
||||
def _local(tag: str) -> str:
|
||||
if "}" in tag:
|
||||
return tag.rsplit("}", 1)[-1]
|
||||
return tag
|
||||
|
||||
|
||||
def run_element_text(run_el) -> str:
|
||||
"""
|
||||
Text of a w:r including non-breaking hyphens.
|
||||
|
||||
md2gost writes ASCII '-' as w:noBreakHyphen (python-docx run.text skips it).
|
||||
Soft hyphens are optional break hints — omit them from Markdown.
|
||||
"""
|
||||
if run_el is None:
|
||||
return ""
|
||||
parts: list[str] = []
|
||||
for child in run_el:
|
||||
tag = _local(child.tag)
|
||||
if tag == "t":
|
||||
parts.append(child.text or "")
|
||||
elif tag == "noBreakHyphen":
|
||||
parts.append("-")
|
||||
elif tag == "softHyphen":
|
||||
continue
|
||||
elif tag == "tab":
|
||||
parts.append("\t")
|
||||
elif tag == "br":
|
||||
# page/line break inside run — treat as space for inline text
|
||||
if child.get(qn("w:type")) == "page":
|
||||
continue
|
||||
parts.append("\n")
|
||||
elif tag == "cr":
|
||||
parts.append("\n")
|
||||
return "".join(parts)
|
||||
|
||||
|
||||
def hyperlink_element_text(hyperlink_el) -> str:
|
||||
if hyperlink_el is None:
|
||||
return ""
|
||||
parts: list[str] = []
|
||||
for run in hyperlink_el.findall(qn("w:r")):
|
||||
parts.append(run_element_text(run))
|
||||
return "".join(parts)
|
||||
|
||||
|
||||
def paragraph_element_text(p_el) -> str:
|
||||
"""Visible body text of w:p (runs + hyperlinks), without OMML."""
|
||||
if p_el is None:
|
||||
return ""
|
||||
parts: list[str] = []
|
||||
for child in p_el:
|
||||
tag = child.tag
|
||||
if tag == qn("w:r"):
|
||||
parts.append(run_element_text(child))
|
||||
elif tag == qn("w:hyperlink"):
|
||||
parts.append(hyperlink_element_text(child))
|
||||
return "".join(parts)
|
||||
|
||||
|
||||
def paragraph_plain(paragraph) -> str:
|
||||
"""Strip CR/bell from a python-docx Paragraph, keeping noBreakHyphen as '-'."""
|
||||
return paragraph_raw(paragraph).strip()
|
||||
|
||||
|
||||
def paragraph_raw(paragraph) -> str:
|
||||
"""Full paragraph text with noBreakHyphen → '-', without strip (for Code lines)."""
|
||||
try:
|
||||
text = paragraph_element_text(paragraph._element)
|
||||
except Exception:
|
||||
text = paragraph.text or ""
|
||||
return text.replace("\r", "").replace("\x07", "")
|
||||
Reference in New Issue
Block a user