feat: MergeHandler + TableExtractor(forward_fill / 表格提取)

This commit is contained in:
lhl
2026-08-08 23:03:29 +08:00
parent b5bd21b334
commit 63d0c90940
3 changed files with 110 additions and 0 deletions
+20
View File
@@ -0,0 +1,20 @@
from __future__ import annotations
from typing import Any
def forward_fill(
matrix: list[list[Any]],
merged_ranges: list[tuple[int, int, int, int]],
) -> list[list[Any]]:
"""合并单元格:用左上角主格值填充范围内全部单元格。"""
out = [list(row) for row in matrix]
for (min_row, min_col, max_row, max_col) in merged_ranges:
if not out or min_row > len(out) or min_col > len(out[min_row - 1]):
continue
main_value = out[min_row - 1][min_col - 1]
for r in range(min_row, min(max_row, len(out)) + 1):
row = out[r - 1]
for c in range(min_col, min(max_col, len(row)) + 1):
row[c - 1] = main_value
return out
+50
View File
@@ -0,0 +1,50 @@
from __future__ import annotations
from typing import Any
from genesis.data_models import CellValue, ExcelTable, Provenance, SheetType
def column_letter(index: int) -> str:
"""1 → A、27 → AA。"""
letters = ""
while index > 0:
index, rem = divmod(index - 1, 26)
letters = chr(65 + rem) + letters
return letters
def extract_table(
sheet_name: str,
matrix: list[list[Any]],
file_name: str,
detected_type: SheetType,
header_row: int = 0,
) -> ExcelTable:
"""从矩阵提取表格:首行视为表头,其后为数据行。"""
if not matrix:
return ExcelTable(
name=sheet_name, detected_type=detected_type,
extraction_method="openpyxl", headers=[], rows=[],
)
headers = [str(c) if c is not None else "" for c in matrix[header_row]]
rows = []
for r in range(header_row + 1, len(matrix)):
row_dict = {}
for c, h in enumerate(headers):
raw = matrix[r][c] if c < len(matrix[r]) else None
row_dict[h] = CellValue(
value=raw,
provenance=Provenance(
file_name=file_name,
sheet_name=sheet_name,
row=r - header_row, # 数据行号从 1 开始
column=column_letter(c + 1),
column_header=h,
),
)
rows.append(row_dict)
return ExcelTable(
name=sheet_name, detected_type=detected_type,
extraction_method="openpyxl", headers=headers, rows=rows,
)