Heuristic: a short textual row from a comparison/categorization table.
(text: str)
| 87 | |
| 88 | |
| 89 | def _looks_like_text_table_row(text: str) -> bool: |
| 90 | """Heuristic: a short textual row from a comparison/categorization table.""" |
| 91 | raw = text.strip() |
| 92 | cleaned = normalize_whitespace(raw) |
| 93 | tokens = cleaned.split() |
| 94 | if len(tokens) < 3 or len(cleaned) > 180: |
| 95 | return False |
| 96 | |
| 97 | cells = [cell.strip() for cell in _TEXT_TABLE_SEPARATOR_RE.split(raw) if cell.strip()] |
| 98 | if len(cells) >= 3 and all(len(cell.split()) <= 8 for cell in cells): |
| 99 | return True |
| 100 | |
| 101 | normalized_tokens = [tok.strip(".,:()[]{}").lower() for tok in tokens] |
| 102 | if cleaned.endswith((".", "?", "!")): |
| 103 | return False |
| 104 | if normalized_tokens[0] in _TEXT_TABLE_PROSE_STARTERS: |
| 105 | return False |
| 106 | if any(tok in _TEXT_TABLE_PROSE_CONNECTORS for tok in normalized_tokens): |
| 107 | return False |
| 108 | |
| 109 | average_token_length = sum(len(tok.strip(".,:()[]{}")) for tok in tokens) / len(tokens) |
| 110 | long_tokens = sum(1 for tok in tokens if len(tok.strip(".,:()[]{}")) > 18) |
| 111 | return len(tokens) <= 8 and average_token_length <= 9.0 and long_tokens <= 1 |
| 112 | |
| 113 | |
| 114 | def _rect_area(bbox: tuple[float, float, float, float]) -> float: |