isolate
isolate
¶
Run-splitting primitives and the cross-run text replacement built on them.
Word splits a paragraph into runs for reasons that have nothing to do with formatting — spell-check state, language tagging, revision marks, the rsid bookkeeping it uses to track editing sessions. A string a reader sees as one word is routinely three runs, so anything that searches or edits paragraph text one run at a time misses most matches.
The primitive here is isolate_range: given a character range measured against
CT_P.text, split the runs covering it so that the range is covered by whole runs and
nothing else, with each original run's w:rPr carried onto the pieces it was divided
into. Everything else — replacement, and reformatting a range — builds on that.
Offsets are measured in the same character space as CT_P.text, so w:tab counts as
one character and a text-wrapping w:br as one newline. A w:instrText contributes
nothing: it holds a field instruction rather than document text, and splitting one
corrupts the field.
_Atom
¶
Bases: NamedTuple
One text-bearing run child, located in the paragraph's character space.
is_divisible
property
¶
True when this atom's text can be cut at an interior offset.
Only w:t holds a string of arbitrary length. Every other text-bearing child
maps to a fixed one-character string — a tab is one "\t" — so a boundary can
fall on either side of it but never inside it.
iter_runs
¶
iter_runs(element: BaseOxmlElement) -> Iterator[CT_R]
Generate each w:r contributing text to element, in document order.
A w:hyperlink is descended into, since its runs are part of the paragraph's text,
and a w:sdt is looked through the same way iter_run_content does.
Source code in src/docx/oxml/text/isolate.py
isolate_range
¶
Split the runs of p so [start, end) is covered by whole runs, and return them.
Each returned run lies entirely within the range, and together they cover it. The formatting of every original run is preserved on each piece it was divided into.
An empty list is returned for an empty range, and for a range beyond the end of the
paragraph's text. Raises ValueError for a reversed or negative range.
Source code in src/docx/oxml/text/isolate.py
replace_range
¶
replace_range(
p: CT_P, start: int, end: int, text: str
) -> None
Replace the characters of p in [start, end) with text.
The replacement takes the formatting of the run holding the first replaced character, which is what Word's own Find and Replace does and what callers expect. When the range spans several runs the remaining matched text is removed from each of them and their formatting goes with it; the runs themselves are left in place, so a hyperlink, bookmark or field partly covered by the range keeps its structure.