From e8d153b5d80685e32bd21ed80b3f9206cdbed2a6 Mon Sep 17 00:00:00 2001 From: umsangdon Date: Sat, 19 Sep 2026 08:25:21 +0900 Subject: [PATCH] =?UTF-8?q?knowledge(=ED=92=88=EC=85=88md):=20=EB=8F=84?= =?UTF-8?q?=EA=B5=AC=20check=20=E2=80=94=20=EA=B0=80=EB=A1=9C=EB=A1=9C=20?= =?UTF-8?q?=EB=88=95=ED=9E=8C=20=EC=AA=BD=20=EC=98=86=20=EB=9D=A0=20?= =?UTF-8?q?=EC=AA=BD=20=EB=B2=88=ED=98=B8=EB=A5=BC=20=EC=AA=BD=20=EA=BC=AC?= =?UTF-8?q?=EB=A6=AC=EB=A1=9C=20=EB=BA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 건설 813~817쪽(책에서 유일한 가로 쪽)은 쪽 번호만 글자층 맨 끝(홀수)·맨 앞(짝수) 줄로 남아 결손으로 뜸 - 가로 쪽이고 그 줄이 수만일 때만 뺌 · 세로 쪽은 그대로 · 시험 1개 추가 Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01V1MKKZKpUHTPKb513FneU8 --- .../original/_pipeline/pum_md_tool.py | 17 +++++++++++++++-- resources/tester/test_pum_md_tool.py | 18 ++++++++++++++++++ 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/resources/knowledge/original/_pipeline/pum_md_tool.py b/resources/knowledge/original/_pipeline/pum_md_tool.py index 42f72b74..9e86a673 100644 --- a/resources/knowledge/original/_pipeline/pum_md_tool.py +++ b/resources/knowledge/original/_pipeline/pum_md_tool.py @@ -193,10 +193,21 @@ _SLOT = re.compile(r"(?:([^/]+)/)?제(\d+)장_[^/]*/(\d+-\d+(?:-\d+)?)_") _MAX_PAGES = 40 +def _side_number(page, row: str) -> bool: + """가로로 눕힌 쪽(건설 813~817)의 옆 띠 쪽 번호 — 맨 끝(홀수 쪽) 또는 맨 앞(짝수 쪽) 줄에 수만 남음.""" + return page.rect.width > page.rect.height and row.isdigit() + + +def _is_footer(page, row: str, footer: re.Pattern) -> bool: + return bool(footer.match(row)) or _side_number(page, row) + + def _body_rows(page, footer: re.Pattern) -> list[str]: """쪽의 줄 — 맨 아래 쪽 꼬리(쪽 번호 · 장 이름)와 이어짐 표지 「→」 는 뺌.""" rows = [row.strip() for row in _page_rows(page)] - if rows and footer.match(rows[-1]): + if rows and _side_number(page, rows[0]): + rows = rows[1:] + if rows and _is_footer(page, rows[-1], footer): rows = rows[:-1] return [row for row in rows if row != "→"] @@ -385,8 +396,10 @@ def pdf_lines(doc, head: dict[str, str], footer: re.Pattern) -> list[tuple[int, out = [] for number in range(start_page, min(end_page, last) + 1): rows = [row.strip() for row in read_rows(doc[number - 1])] - if rows and footer.match(rows[-1]): + if rows and _is_footer(doc[number - 1], rows[-1], footer): rows[-1] = "" # 쪽 꼬리 + if rows and _side_number(doc[number - 1], rows[0]): + rows[0] = "" # 눕힌 쪽 옆 띠 쪽 번호 for index, row in enumerate(rows): if (number, index) < (start_page, start_row) or (number, index) >= (end_page, end_row): continue diff --git a/resources/tester/test_pum_md_tool.py b/resources/tester/test_pum_md_tool.py index 9266dadc..d896abb5 100644 --- a/resources/tester/test_pum_md_tool.py +++ b/resources/tester/test_pum_md_tool.py @@ -172,6 +172,24 @@ def test_repeated_head_comment_counts_and_footer_dropped(): assert tool.verdict(tool.compare(pdf, tool.md_lines(md))).startswith("통과") +def test_landscape_page_side_number_is_footer(): + """가로로 눕힌 쪽은 옆 띠 쪽 번호(맨 끝·맨 앞 줄 · 수만)를 꼬리로 뺌 · 세로 쪽의 맨 앞·끝 수 줄은 본문으로 둠.""" + pymupdf = pytest.importorskip("pymupdf") + doc = pymupdf.open() + pages = ( + ((842, 595), ["9-5. A", "X 1.0", "757"]), + ((842, 595), ["758", "Z 3.0"]), + ((595, 842), ["7", "Y 2.0", "10"]), + ) + for size, lines in pages: + page = doc.new_page(width=size[0], height=size[1]) + for n, text in enumerate(lines): + page.insert_text((72, 72 + 30 * n), text) + head = {"PDF쪽": "1~3", "시작표지": "9-5. A", "끝표지": "끝"} + pdf = tool.pdf_lines(doc, head, tool.BOOKS["산림"]["footer"]) + assert [row for _, row in pdf] == ["9-5. A", "X 1.0", "Z 3.0", "7", "Y 2.0", "10"] + + def test_off_layer_glyphs_and_compat_han(): """사용자 영역 글리프는 ①② 에서 빼고 드러냄 · md 는 감싼 받아쓰기를 뺌 · 호환 한자는 통합 한자로(NFKC 통째 아님).""" pdf = [(21, "체적 V \ue001\ue002 = 1.5"), (21, "공극\uf9db ㎥ ①")]