knowledge(품셈md): 도구 「글자층 붙은 수」 주석으로 PDF 쪽 붙은 수 가름 · 시험 하나

- md 주석 <!-- 글자층 붙은 수: 「0.3350.335」→「0.335 0.335」 --> 에 적힌 글자열만 PDF 쪽에서 가름(자간 벌린 수의 거꾸로)
- PDF 에 있고 왼쪽이 오른쪽에서 공백만 뺀 것일 때만 · 기계검사 칸 「글자층 붙은 수 N곳」 · 못 쓰면 불통
- 전후 대조: 기계검사 칸 있는 md 518개 판정 바뀜 0

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V1MKKZKpUHTPKb513FneU8
This commit is contained in:
2026-09-19 09:18:43 +09:00
co-authored by Claude Opus 5
parent 23453c36b6
commit f4e142b38a
2 changed files with 59 additions and 11 deletions
@@ -494,20 +494,35 @@ def compare(pdf: list[tuple[int, str]], md: list[tuple[int, str]]) -> dict:
#: 짐작으로 붙이지 않고 **적힌 글자열만** PDF 쪽에서 붙여 셈 · 오른쪽은 왼쪽에서 공백만 뺀 것이어야 함.
_SPACED = re.compile(r"<!--\s*자간 벌린 수:(.*?)-->", re.S)
_SPACED_PAIR = re.compile(r"「([^」]+)」\s*→\s*「([^」]+)」")
#: 글자층 붙은 수 — 자간 벌린 수의 거꾸로. 글자층이 여러 칸 값을 공백 없이 한 덩이로 담은 것
#: md 주석 `<!-- 글자층 붙은 수: 「0.3350.335」→「0.335 0.335」 -->` · 왼쪽은 오른쪽에서 공백만 뺀 것이어야 함.
_GLUED = re.compile(r"<!--\s*글자층 붙은 수:(.*?)-->", re.S)
def _rewrite(pdf: list[tuple[int, str]], body: str, mark: re.Pattern, ok):
"""(PDF 줄, 고친 곳 수, 못 쓴 글자열) — md 주석에 적힌 글자열만 PDF 줄에서 바꿈(PDF 에 있고 ok 일 때만)."""
done, bad = 0, []
for block in mark.findall(body):
for old, new in _SPACED_PAIR.findall(block):
hits = sum(line.count(old) for _, line in pdf)
if not hits or not ok(old, new):
bad.append(old)
continue
pdf = [(at, line.replace(old, new)) for at, line in pdf]
done += hits
return pdf, done, bad
def join_spaced_numbers(pdf: list[tuple[int, str]], body: str):
"""(PDF 줄, 붙인 곳 수, 못 쓴 글자열) — md 주석에 적힌 자간 벌린 수만 PDF 줄에서 붙임."""
joined, bad = 0, []
for block in _SPACED.findall(body):
for spaced, tight in _SPACED_PAIR.findall(block):
hits = sum(line.count(spaced) for _, line in pdf)
if not hits or re.sub(r"\s", "", spaced) != tight:
bad.append(spaced)
continue
pdf = [(at, line.replace(spaced, tight)) for at, line in pdf]
joined += hits
return pdf, joined, bad
return _rewrite(pdf, body, _SPACED, lambda spaced, tight: re.sub(r"\s", "", spaced) == tight)
def split_glued_numbers(pdf: list[tuple[int, str]], body: str):
"""(PDF 줄, 가른 곳 수, 못 쓴 글자열) — md 주석에 적힌 글자층 붙은 수만 PDF 줄에서 가름."""
return _rewrite(
pdf, body, _GLUED, lambda glued, split: glued != split and re.sub(r"\s", "", split) == glued
)
def verdict(result: dict) -> str:
@@ -518,7 +533,8 @@ def verdict(result: dict) -> str:
sum(result["char_extra"].values()),
)
joined, bad = result.get("spaced", (0, []))
word = "통과" if not any(counts) and not bad else "불통"
split, bad_glued = result.get("glued", (0, []))
word = "통과" if not any(counts) and not bad and not bad_glued else "불통"
line = (
f"{word} · ①수 결손 {counts[0]} 허구 {counts[1]} · ②글자 빠짐 {counts[2]} 더함 {counts[3]}"
)
@@ -530,6 +546,10 @@ def verdict(result: dict) -> str:
line += f" · 자간 벌린 수 {joined}곳"
if bad:
line += " · 자간 벌린 수 못 씀 " + " ".join(f"「{s}」" for s in bad)
if split: # ③ 이 그림으로 칸마다 값을 꼭 보게
line += f" · 글자층 붙은 수 {split}곳"
if bad_glued:
line += " · 글자층 붙은 수 못 씀 " + " ".join(f"「{s}」" for s in bad_glued)
return line
@@ -555,8 +575,10 @@ def check_file(path: Path) -> tuple[dict, str]:
with pymupdf.open(book["pdf"]) as doc:
pdf = pdf_lines(doc, read_head(path), book["footer"])
pdf, joined, bad = join_spaced_numbers(pdf, body)
pdf, split, bad_glued = split_glued_numbers(pdf, body)
result = compare(pdf, md_lines(body))
result["spaced"] = (joined, bad)
result["glued"] = (split, bad_glued)
return result, verdict(result)