Skip to content

fix: keep letter-spaced text whole under the word-gap cap - #358

Closed
wittjeff wants to merge 1 commit into
docling-project:mainfrom
wittjeff:fix/word-gap-threshold
Closed

wittjeff wants to merge 1 commit into
docling-project:mainfrom
wittjeff:fix/word-gap-threshold

Conversation

@wittjeff

@wittjeff wittjeff commented Sep 26, 2026 •

Copy link
Copy Markdown
Contributor

Re-scoped on 2026-10-05: #355 was fixed by #361 (7.22.1). This PR now fixes the regression that #361's flat cap introduced on letter-spaced text.

Problem

Since 7.22.1, contract() caps the unmarked word-gap threshold at a flat 0.35 advance on every line. Letter spacing opens every character gap on a line, often past 0.35, so tracked text splits into letters. Line cells:

file 7.22.0 7.22.2 (main) this PR
elsevier-00.pdf p1 ARTICLE INFO A R T I C L E I N F O ARTICLE INFO
14289803404128846560-14.pdf p14 Tinta T i nt a Tinta
14289803404128846560-14.pdf Ga b i ne t e de Ap o i o à s F r e g ue s i a s Gabinete de Apoio às Freguesias
2305.03393v1-pg9.pdf (#355) HyperParameterOptimization (7.21–7.22.0) 5.1 Hyper Parameter Optimization 5.1 Hyper Parameter Optimization

Change

infer_word_gap() keeps the cap, but lets it rise with the line's own letter spacing:

cap = max(0.35, 1.5 × median + 0.20)

The median is taken over the gaps between non-dot glyphs that fall below the word threshold. Leader dots are spaced like words and would otherwise pass for tracking (maximum mass of vehicle: . . . . collapsed to maximummassofvehicle: without that exclusion). The cap only rises when at least three such gaps exist: a single gap, as between a lone math symbol or one table digit and its neighbour, is no evidence of tracking.

Tests:

Results

Regression dataset, line cells compared with main (7.22.2), 447 files:

lines files pages
boundaries removed 926 33 82
boundaries added 0 0 0
  • None of the 926 merges glues two dictionary words together; 109 join letters into a dictionary word (Subst i tut ing → Substituting, heff ingen → heffingen, C H A P T E R 5 → CHAPTER 5, F INANCI ALS → FINANCIALS).
  • 665 of them restore the 7.22.0 line text exactly. Most of the rest are the Portuguese letter-spaced file above (617 lines in all), where 7.22.0 had its own partial splits.
  • Merges that are not tracked text: isolated math and music glyphs (F t dt → Ftdt in 19246029784032167-4.pdf, œ œ œ note heads in 4561257296328379730-2.pdf), and a Japanese name list where 7.22.0 also merged (岩 田 守 弘 → 岩田 守弘).
  • Every line listed in Words lose their separating spaces in 7.21.0 ("Related Work" -> "RelatedWork"), bisected to #351 #355 is unchanged from main.

Ground truth. The 82 pages above are the ones whose line cells differ from main, so test_regression_parse.py fails on them and the dataset revision would need regenerating. I have not touched tests/constants.py.

Not addressed

  • a b s t r a c t in elsevier-00.pdf becomes abs trac t: the Tc on that line puts two gaps above the cap. Still closer than main.
  • The single-digit grid in 10458169359009391401-5.pdf stays as on main (the three-gap rule keeps it), although 7.22.0 merged some of its cells.

🤖 Generated with Claude Code

@github-actions

Copy link
Copy Markdown
Contributor

✅ DCO Check Passed

Thanks @wittjeff, all your commits are properly signed off. 🎉

@mergify

mergify Bot commented Sep 26, 2026

Copy link
Copy Markdown
Contributor

Merge Protections

🟢 Merge protection satisfied — ready to merge.

Show 1 satisfied protection

🟢 Enforce conventional commit

Make sure that we follow https://www.conventionalcommits.org/en/v1.0.0/

  • title ~= ^(fix|feat|docs|style|refactor|perf|test|build|ci|chore|revert)(?:\(.+\))?(!)?:

@PeterStaar-IBM
PeterStaar-IBM self-requested a review September 27, 2026 05:44
@wittjeff
wittjeff force-pushed the fix/word-gap-threshold branch from 2db032d to af3220a Compare October 4, 2026 18:34
@PeterStaar-IBM

Copy link
Copy Markdown
Member

@wittjeff I think this has been fixed by now, no?

@wittjeff

wittjeff commented Oct 5, 2026

Copy link
Copy Markdown
Contributor Author

@PeterStaar-IBM yes, #361 fixes #355: on 7.22.2 the page-9 heading reads 5.1 Hyper Parameter Optimization, and the section-heading test from this PR passes on main.

One thing this PR's second test surfaces: the flat 0.35 cap in contract() splits letter-spaced headings. elsevier-00.pdf's ARTICLE INFO was whole in 7.22.0 and is A R T I C L E I N F O in 7.22.1+ (it was also split in 7.20.0). I'm re-scoping this PR to that regression: replace the flat cap with the median-relative one, which handles both the section-number gap and tracked text. I'll update the description and numbers against current main.

Since 7.22.1 (docling-project#361), contract() caps the unmarked word-gap threshold at
a flat 0.35 advance on every line. That fixed the lost word boundaries of
docling-project#355, but letter spacing opens every character gap on a line, often past
0.35, so tracked text now splits into letters: "ARTICLE INFO" in
elsevier-00.pdf reads "A R T I C L E I N F O", a letter-spaced table cell
in 14289803404128846560-14.pdf reads "T i nt a". Both were whole in 7.22.0.

The cap now starts at 0.35 and rises with the line's own letter spacing:
1.5 times the median character-cluster gap plus 0.20, measured over gaps
between non-dot glyphs so leader dots do not pass for tracking, and only
when at least three such gaps exist. Runs without space glyphs apply it to
the k-means midpoint as before; runs with space glyphs apply it in place of
the flat 0.35, bounded by one advance.

On the regression dataset the change only removes boundaries relative to
main: 926 lines in 33 files, none of them gluing two dictionary words, and
two thirds of them restoring the 7.22.0 line text. No new boundaries appear.

Signed-off-by: Jeff Witt <1848307+wittjeff@users.noreply.github.com>
@wittjeff
wittjeff force-pushed the fix/word-gap-threshold branch from af3220a to 579ef02 Compare October 5, 2026 13:18
@wittjeff wittjeff changed the title fix: cap the inferred word-gap threshold by the character gaps fix: keep letter-spaced text whole under the word-gap cap Oct 5, 2026
@wittjeff

wittjeff commented Oct 5, 2026

Copy link
Copy Markdown
Contributor Author

Re-scoped and pushed (579ef02). The flat 0.35 cap now rises with the line's own letter spacing: max(0.35, 1.5 × median letter gap + 0.20), with gaps next to leader dots excluded and at least three letter gaps required. On a line that is not letter-spaced the threshold is exactly main's.

Against main on the regression set, the change only removes boundaries: 926 lines in 33 files (82 pages), none gluing two dictionary words, 665 of them back to their 7.22.0 text. No new boundaries anywhere, and every line from #355 is unchanged. Description and tables updated; the ground truth for those 82 pages would need regenerating.

seanphopkins added a commit to seanphopkins/docling-parse that referenced this pull request Oct 6, 2026
…-project#377)

The letter-spacing branch shared the half-space gate of the small-gap
branch, so tracking at 0.6-0.8 of a space never reached it (found on docling-project#385:
Portuguese Calibri text tracked at ~0.7 of a space stayed one word per
letter). The small-gap branch keeps its half-space floor; the
letter-spacing branch, which carries its own same-font and same-segment
evidence, now admits gaps under 0.8 of the run's space.

Swept 0.5 to 1.0 on the 940 regression pages: 0.8 makes those words whole
with no join beyond what this PR or docling-project#358 already make, apart from one
split dot leader joined and a partial join of a letter-split Japanese
word; at 1.0 positioned maths symbols join (:,).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Sean Hopkins <sean.p.hopkins@gmail.com>
@wittjeff
wittjeff marked this pull request as ready for review October 21, 2026 11:52
@cau-git

cau-git commented Oct 28, 2026

Copy link
Copy Markdown
Member

Thanks for this contribution. This PR is on hold until it has been consolidated as described in #428. Please resubmit it as part of the topic PR listed there, with the evidence the issue asks for.

@wittjeff

wittjeff commented Nov 2, 2026

Copy link
Copy Markdown
Contributor Author

Superseded by #437, the word and cell segmentation topic PR from #428. It carries this change as one commit, rebased on main, with the evidence and the ground-truth page list in one place.

@wittjeff wittjeff closed this Nov 2, 2026
wittjeff added a commit to wittjeff/docling-parse that referenced this pull request Nov 2, 2026
… spacing

Since 7.22.1 (docling-project#361) an unmarked gap above 0.35 neighbouring advances
starts a word on every line. Letter spacing opens every gap of a tracked
line, often past that, so tracked text that carries space glyphs split
into letters: `Tinta` -> `T i nt a` and `Gabinete de Apoio às
Freguesias` -> `Ga b i ne t e de Ap o i o à s F r e g ue s i a s` in
14289803404128846560-14.pdf.

On a run with space glyphs the threshold is now 1.5 times the median
unmarked gap below one advance plus 0.20, at least 0.35 and at most 1.0,
when three or more such gaps exist between glyphs that are not leader
dots. Runs without space glyphs are not touched: the em rule of the
previous commits removes their letter spacing up to 0.2 em, and wider
tracking (`a r t i c l e i n f o` in elsevier-00.pdf, 0.44 em) stays a
known limit, as docling-project#358 and docling-project#409 both documented.

Replaces docling-project#358 (follow-up to docling-project#355).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: Jeff Witt <1848307+wittjeff@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants