diff --git a/src/genesis/parsers/sheet_nature.py b/src/genesis/parsers/sheet_nature.py new file mode 100644 index 0000000..d77c825 --- /dev/null +++ b/src/genesis/parsers/sheet_nature.py @@ -0,0 +1,44 @@ +from __future__ import annotations + +from enum import Enum +from typing import Any + + +class SheetNature(Enum): + TABLE = "table" + FREE_TEXT = "free_text" + MIXED = "mixed" + + +def _non_empty(row: list[Any]) -> list[Any]: + return [c for c in row if c is not None and str(c).strip() != ""] + + +def find_header_row(matrix: list[list[Any]]) -> int: + for i, row in enumerate(matrix): + if len(_non_empty(row)) >= 2: + return i + return -1 + + +def _free_text_like(matrix: list[list[Any]]) -> bool: + if not matrix: + return True + max_cols = max((len(row) for row in matrix), default=0) + if max_cols <= 1: + return True + non_empty_rows = [r for r in matrix if _non_empty(r)] + if len(non_empty_rows) / len(matrix) < 0.7: + return True + return find_header_row(matrix) == -1 + + +def classify_sheet(matrix: list[list[Any]]) -> SheetNature: + if _free_text_like(matrix): + return SheetNature.FREE_TEXT + header_row = find_header_row(matrix) + if header_row >= 0: + for row in matrix[header_row + 1:]: + if any(str(c).strip().startswith(("・", "■")) for c in _non_empty(row)): + return SheetNature.MIXED + return SheetNature.TABLE \ No newline at end of file diff --git a/tests/test_sheet_nature.py b/tests/test_sheet_nature.py new file mode 100644 index 0000000..8320271 --- /dev/null +++ b/tests/test_sheet_nature.py @@ -0,0 +1,22 @@ +from genesis.parsers.sheet_nature import SheetNature, classify_sheet, find_header_row + + +def test_table_detection(): + m = [["機能ID", "機能名"], ["A001", "社員登録"], ["A002", "退職処理"]] + assert classify_sheet(m) == SheetNature.TABLE + + +def test_free_text_single_col(): + m = [["新入社員を登録できる。"], ["氏名・所属・入社日を入力する。"]] + assert classify_sheet(m) == SheetNature.FREE_TEXT + + +def test_free_text_many_empty_rows(): + m = [["要求A"], [], [], [], ["要求B"]] + assert classify_sheet(m) == SheetNature.FREE_TEXT + + +def test_header_row_index(): + m = [["機能ID", "名前"], ["1", "田中"]] + assert find_header_row(m) == 0 + assert find_header_row([["自由テキスト"]]) == -1 \ No newline at end of file