1+ import html
12import re
23import unicodedata
34
@@ -43,6 +44,15 @@ class TextCleaner:
4344
4445 # End-of-line soft hyphens: "word-\n" or "word- \n" followed by continuation
4546 _HYPHEN_RE = re .compile (r"(\w)- ?\n(\w)" )
47+ _TABLE_RE = re .compile (r"<table\b[^>]*>.*?</table>" , re .IGNORECASE | re .DOTALL )
48+ _ROW_RE = re .compile (r"<tr\b[^>]*>(.*?)</tr>" , re .IGNORECASE | re .DOTALL )
49+ _CELL_RE = re .compile (r"<t[dh]\b[^>]*>(.*?)</t[dh]>" , re .IGNORECASE | re .DOTALL )
50+ _BR_RE = re .compile (r"<br\s*/?>" , re .IGNORECASE )
51+ _PARA_END_RE = re .compile (r"</(?:p|div|h[1-6])\s*>" , re .IGNORECASE )
52+ _HTML_TAG_RE = re .compile (
53+ r"</?(?:center|div|span|html|body|table|thead|tbody|tfoot|tr|td|th|p|br|h[1-6])\b[^>]*>" ,
54+ re .IGNORECASE ,
55+ )
4656
4757 def clean (self , text : str , strip_refs : bool = False ) -> str :
4858 """Full cleaning pipeline."""
@@ -53,6 +63,7 @@ def clean(self, text: str, strip_refs: bool = False) -> str:
5363 text = self ._strip_ref_blocks (text )
5464 text = self ._strip_model_tokens (text )
5565 text = self ._strip_artifacts (text )
66+ text = self ._html_to_text (text )
5667 text = self ._rejoin_hyphens (text )
5768 text = self ._normalize_whitespace (text )
5869 text = self ._fix_common_ocr_issues (text )
@@ -96,6 +107,30 @@ def _strip_artifacts(self, text: str) -> str:
96107 text = pattern .sub ("" , text )
97108 return text
98109
110+ def _html_to_text (self , text : str ) -> str :
111+ """Convert occasional model-emitted HTML into readable plain text."""
112+ text = self ._TABLE_RE .sub (lambda match : self ._table_to_text (match .group (0 )), text )
113+ text = self ._BR_RE .sub ("\n " , text )
114+ text = self ._PARA_END_RE .sub ("\n " , text )
115+ text = self ._HTML_TAG_RE .sub ("" , text )
116+ return html .unescape (text )
117+
118+ def _table_to_text (self , table : str ) -> str :
119+ rows : list [str ] = []
120+
121+ for row_match in self ._ROW_RE .finditer (table ):
122+ cells : list [str ] = []
123+ for cell_match in self ._CELL_RE .finditer (row_match .group (1 )):
124+ cell = self ._HTML_TAG_RE .sub ("" , cell_match .group (1 ))
125+ cell = html .unescape (cell )
126+ cell = re .sub (r"\s+" , " " , cell ).strip ()
127+ if cell :
128+ cells .append (cell )
129+ if cells :
130+ rows .append (" | " .join (cells ))
131+
132+ return "\n " .join (rows )
133+
99134 def _normalize_whitespace (self , text : str ) -> str :
100135 # Replace multiple blank lines with a single blank line
101136 text = re .sub (r"\n{3,}" , "\n \n " , text )
0 commit comments