Fix tables where docling expanded merged cells by repeating content across columns. Strategy: process row by row within each table. - If ALL non-empty cells in a row are identical (merged-cell row), collapse to 1 cell and render as a bold heading row: | **content** | - Otherw
(content: str)
| 315 | |
| 316 | |
| 317 | def deduplicate_table_columns(content: str) -> tuple[str, int]: |
| 318 | """ |
| 319 | Fix tables where docling expanded merged cells by repeating content across columns. |
| 320 | |
| 321 | Strategy: process row by row within each table. |
| 322 | - If ALL non-empty cells in a row are identical (merged-cell row), collapse to 1 cell |
| 323 | and render as a bold heading row: | **content** | |
| 324 | - Otherwise keep the row as-is. |
| 325 | |
| 326 | Only applies to tables with >= 3 columns where at least one row has all-identical cells. |
| 327 | """ |
| 328 | lines = content.split('\n') |
| 329 | blocks = split_into_table_blocks(lines) |
| 330 | fixed = 0 |
| 331 | out_blocks = [] |
| 332 | |
| 333 | for btype, blines in blocks: |
| 334 | if btype != 'table': |
| 335 | out_blocks.append((btype, blines)) |
| 336 | continue |
| 337 | |
| 338 | # Determine column count from first non-separator row |
| 339 | data_rows = [l for l in blines if l.strip() and not is_separator_row(l)] |
| 340 | if not data_rows: |
| 341 | out_blocks.append((btype, blines)) |
| 342 | continue |
| 343 | |
| 344 | col_count = len(parse_table_row(data_rows[0])) |
| 345 | if col_count < 3: |
| 346 | out_blocks.append((btype, blines)) |
| 347 | continue |
| 348 | |
| 349 | # Check if any row has all-identical non-empty cells (merged-cell indicator) |
| 350 | has_merged = False |
| 351 | for row in data_rows: |
| 352 | cells = parse_table_row(row) |
| 353 | non_empty = [c for c in cells if c.strip()] |
| 354 | if len(non_empty) >= 2 and len(set(non_empty)) == 1: |
| 355 | has_merged = True |
| 356 | break |
| 357 | |
| 358 | if not has_merged: |
| 359 | out_blocks.append((btype, blines)) |
| 360 | continue |
| 361 | |
| 362 | # Rebuild: collapse all-identical rows to a single bold heading cell |
| 363 | new_blines = [] |
| 364 | separator_written = False |
| 365 | for line in blines: |
| 366 | if not line.strip(): |
| 367 | new_blines.append(line) |
| 368 | continue |
| 369 | if is_separator_row(line): |
| 370 | if not separator_written: |
| 371 | new_blines.append('| ' + ' | '.join(['---'] * col_count) + ' |') |
| 372 | separator_written = True |
| 373 | continue |
| 374 | cells = parse_table_row(line) |
no test coverage detected