Jelajahi Sumber

feat: 使用 BeautifulSoup 优化 HTML 表格生成,解决现有方法的缺陷并增强稳定性

zhch158_admin 1 bulan lalu
induk
melakukan
a947415159
1 mengubah file dengan 169 tambahan dan 0 penghapusan
  1. 169 0
      zhch/table_recognition_v2-说明.md

+ 169 - 0
zhch/table_recognition_v2-说明.md

@@ -116,6 +116,175 @@ class _TableRecognitionPipelineV2(BasePipeline):
 # ...existing code...
 ````
 
+## BeautifulSoup 生成HTML表格
+正在收集工作区信息正在筛选到最相关的信息基于你的想法,使用 BeautifulSoup 生成表格树然后填充内容确实是一个很好的改进方案。让我比较一下两种方式:
+
+## 现有 get_html_result 的问题
+
+1. **字符串拼接**:逐个拼接 HTML 标签,容易出错
+2. **索引对齐复杂**:需要手动维护 `td_global`、`row_idx`、`col_idx` 等指针
+3. **结构不一致时易崩溃**:当检测列数与结构列数不匹配时需要复杂的回退逻辑
+4. **难以处理合并单元格**:如果后续需要支持 `colspan`/`rowspan` 会很困难
+
+## BeautifulSoup 方案的优势
+
+1. **结构清晰**:直接基于检测到的单元格坐标生成规整的表格结构
+2. **索引简单**:通过行列坐标直接定位单元格,无需复杂的指针推进
+3. **易于扩展**:天然支持合并单元格、样式添加等高级功能
+4. **更稳定**:不依赖于结构识别模型的输出质量
+
+## 推荐的 BeautifulSoup 实现
+
+````python
+def generate_table_from_cells(table_cells_result, ocr_texts_res, table_cells_flag):
+    """
+    基于检测到的单元格坐标生成 BeautifulSoup 表格树并填充内容
+    """
+    from bs4 import BeautifulSoup
+    
+    # 计算表格行列数
+    num_rows = len(table_cells_flag) - 1
+    max_cols = max(table_cells_flag[i+1] - table_cells_flag[i] for i in range(num_rows)) if num_rows > 0 else 0
+    
+    # 创建基础表格结构
+    html_template = f"""
+    <html>
+    <body>
+    <table>
+    {''.join(f'<tr>{"<td></td>" * max_cols}</tr>' for _ in range(num_rows))}
+    </table>
+    </body>
+    </html>
+    """
+    
+    soup = BeautifulSoup(html_template, 'html.parser')
+    table = soup.find('table')
+    rows = table.find_all('tr')
+    
+    # 填充单元格内容
+    for row_idx in range(num_rows):
+        row = rows[row_idx]
+        cells = row.find_all('td')
+        
+        # 获取当前行的单元格范围
+        start_cell = table_cells_flag[row_idx]
+        end_cell = table_cells_flag[row_idx + 1]
+        
+        for col_idx in range(end_cell - start_cell):
+            if col_idx < len(cells):
+                cell_global_idx = start_cell + col_idx
+                
+                # 查找匹配的 OCR 内容
+                cell_content = ""
+                if cell_global_idx < len(ocr_texts_res):
+                    cell_content = ocr_texts_res[cell_global_idx] or ""
+                
+                cells[col_idx].string = cell_content
+    
+    return str(soup)
+````
+
+## 更优化的实现方案
+
+````python
+# ...existing code...
+
+def generate_table_with_beautifulsoup(
+    table_cells_result: list,
+    ocr_texts_res: list, 
+    matched_index: dict,
+    table_cells_flag: list
+) -> str:
+    """
+    使用 BeautifulSoup 生成表格并填充 OCR 内容
+    
+    Args:
+        table_cells_result: 单元格坐标列表
+        ocr_texts_res: OCR 识别文本列表
+        matched_index: 单元格与 OCR 的匹配关系
+        table_cells_flag: 行边界标记
+    
+    Returns:
+        str: 生成的 HTML 表格字符串
+    """
+    try:
+        from bs4 import BeautifulSoup, Tag
+    except ImportError:
+        # 如果没有 BeautifulSoup,回退到原方法
+        return get_html_result_fallback(matched_index, ocr_texts_res, table_cells_flag)
+    
+    # 计算表格维度
+    num_rows = len(table_cells_flag) - 1
+    if num_rows <= 0:
+        return "<html><body><table></table></body></html>"
+    
+    # 创建表格结构
+    soup = BeautifulSoup("<html><body><table></table></body></html>", 'html.parser')
+    table = soup.find('table')
+    
+    # 为每行添加单元格
+    for row_idx in range(num_rows):
+        tr = soup.new_tag('tr')
+        table.append(tr)
+        
+        # 当前行的单元格数量
+        num_cols = table_cells_flag[row_idx + 1] - table_cells_flag[row_idx]
+        
+        for col_idx in range(num_cols):
+            td = soup.new_tag('td')
+            tr.append(td)
+            
+            # 填充单元格内容
+            if row_idx < len(matched_index) and col_idx in matched_index[row_idx]:
+                content_parts = []
+                for ocr_idx in matched_index[row_idx][col_idx]:
+                    if ocr_idx < len(ocr_texts_res):
+                        content = ocr_texts_res[ocr_idx].strip()
+                        if content:
+                            content_parts.append(content)
+                
+                # 合并多个 OCR 结果
+                if content_parts:
+                    td.string = " ".join(content_parts)
+    
+    return str(soup)
+
+def get_table_recognition_res(
+    table_box: list,
+    table_structure_result: list,
+    table_cells_result: list,
+    overall_ocr_res: OCRResult,
+    table_ocr_pred: dict,
+    cells_texts_list: list,
+    use_table_cells_ocr_results: bool,
+    use_table_cells_split_ocr: bool,
+) -> SingleTableRecognitionResult:
+    # ...existing code above...
+    
+    # 使用 BeautifulSoup 生成表格(推荐)
+    pred_html = generate_table_with_beautifulsoup(
+        table_cells_result, ocr_texts_res, matched_index, table_cells_flag
+    )
+    
+    # ...existing code below...
+````
+
+## 结论
+
+**推荐使用 BeautifulSoup 方案**,原因:
+
+1. **更稳定**:不受结构识别模型输出质量影响
+2. **更简洁**:代码逻辑更清晰,易于维护
+3. **更灵活**:容易扩展支持合并单元格、样式等功能
+4. **更可靠**:避免了复杂的指针对齐问题
+
+但需要:
+- 添加 BeautifulSoup 依赖检查
+- 保留原方法作为回退方案
+- 充分测试确保兼容性
+
+这种方案特别适合**有线表格**场景,因为单元格检测通常很准确,可以直接基于检测结果构建表格结构。
+
 ## 单元格内文字丢失
 上期发生额”ocr后的文字bbox是在表格检测单元框内,为什么没有显示出来
 **还需查找原因**