From ba1a0bbc2f7abfa0d0ab21e5cc4ca49089112d4f Mon Sep 17 00:00:00 2001 From: hbyang Date: Thu, 20 Aug 2026 11:36:47 +0900 Subject: [PATCH] =?UTF-8?q?docs:=20=ED=8C=90=EB=A1=80=20=EB=A6=AC=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=EC=97=85=20=EB=B0=B0=ED=8F=AC=EC=9A=A9=20Excel=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CSV 는 UTF-8 BOM 이라 Excel 에서 열리기는 하지만 받는 쪽이 그대로 읽을 수 있는 형태가 아니다. 열 너비·줄바꿈·필터가 없어 판시 요약처럼 긴 칸이 한 줄로 뭉개지고 등급별로 훑어보기도 어렵다. 전달 첨부용 통합문서를 별도로 만든다. docs/판례_리스트업.xlsx — 5개 시트 판례 목록 57건. 등급 색상 구분, 자동 필터, 사건번호까지 틀 고정, 출처 하이퍼링크 요약·방법 검토 단계별 건수(2,085 → 545 → 57), 등급 정의, 핵심 3건 제외 사유 수집 단계 제외분과 적재본에서 뺀 유형 데이터 공백 상담 전 해소가 필요한 4개 항목 + 선덕여왕 항소심 인용 주의 상담 질의 전문가 상담용 질의 5건 표 데이터는 precedent_listup.csv 에서 읽고, 서술 시트는 PRECEDENT_LISTUP.md 를 원본으로 옮겼다. 수치를 스크립트에서 새로 만들지 않는다. 법률 의견서가 아니라 데이터 정리 결과이며 등급·쟁점 요약은 적재 판시를 근거로 부여한 것이라는 단서를 요약 시트에 함께 넣었다. 전달 시 유지해야 한다. Co-Authored-By: Claude Opus 5 (1M context) --- docs/PRECEDENT_LISTUP.md | 5 +- docs/판례_리스트업.xlsx | Bin 0 -> 29570 bytes scripts/build_precedent_listup_xlsx.py | 472 +++++++++++++++++++++++++ 3 files changed, 476 insertions(+), 1 deletion(-) create mode 100644 docs/판례_리스트업.xlsx create mode 100644 scripts/build_precedent_listup_xlsx.py diff --git a/docs/PRECEDENT_LISTUP.md b/docs/PRECEDENT_LISTUP.md index 135f742..251755f 100644 --- a/docs/PRECEDENT_LISTUP.md +++ b/docs/PRECEDENT_LISTUP.md @@ -191,7 +191,10 @@ ## 8. 첨부·원본 위치 -- 본 리스트업 표(CSV, Excel에서 바로 열림): `data/precedents/precedent_listup.csv` +- **배포용 Excel(전달 첨부): `docs/판례_리스트업.xlsx`** — 5개 시트 + (판례 목록 / 요약·방법 / 제외 사유 / 데이터 공백 / 상담 질의). + `scripts/build_precedent_listup_xlsx.py` 로 재생성한다. +- 원본 표(CSV): `data/precedents/precedent_listup.csv` - 운영 적재본 545건: `data/precedents/precedents.jsonl` - 수집·제외 통계: `data/precedents/selection_audit.json` - 데이터 계층 전체 인벤토리: `docs/PRECEDENT_DATA.md` diff --git a/docs/판례_리스트업.xlsx b/docs/판례_리스트업.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..1a920882386d23ec8477e803cc45cd4289af9f88 GIT binary patch literal 29570 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 int: + """시트 상단 제목. 다음에 쓸 행 번호를 돌려준다.""" + ws.cell(row=1, column=1, value=title).font = TITLE_FONT + row = 2 + if subtitle: + cell = ws.cell(row=2, column=1, value=subtitle) + cell.font = NOTE_FONT + cell.alignment = TOP_WRAP + ws.merge_cells(start_row=2, start_column=1, end_row=2, end_column=width_cols) + row = 3 + return row + 1 + + +def _header_row(ws, row: int, labels: list[str]) -> None: + for col, label in enumerate(labels, start=1): + cell = ws.cell(row=row, column=col, value=label) + cell.font = HEAD_FONT + cell.fill = HEAD_FILL + cell.alignment = CENTER + cell.border = CELL_BORDER + + +def _widths(ws, widths: list[int]) -> None: + for i, w in enumerate(widths, start=1): + ws.column_dimensions[get_column_letter(i)].width = w + + +def _body(cell, *, wrap: bool = True) -> None: + cell.font = BODY_FONT + cell.alignment = TOP_WRAP if wrap else TOP_LEFT + cell.border = CELL_BORDER + + +# --------------------------------------------------------------------------- +# 시트 1 — 판례 목록 +# --------------------------------------------------------------------------- + + +def sheet_list(wb: Workbook, rows: list[dict]) -> None: + ws = wb.create_sheet("판례 목록") + counts = Counter(r["grade"] for r in rows) + head = _title_block( + ws, + "자서전·출판물 표절 판단 근거 판례", + f"운영 적재본 545건 전수 검토 → 선정 {len(rows)}건 " + f"(A {counts['A']} · B {counts['B']} · C {counts['C']}). " + "등급 정의와 선정 방법은 '요약·방법' 시트 참조.", + width_cols=len(COLUMNS), + ) + + _header_row(ws, head, [label for _, label, _, _ in COLUMNS]) + _widths(ws, [w for _, _, w, _ in COLUMNS]) + + order = {"A": 0, "B": 1, "C": 2} + rows = sorted(rows, key=lambda r: (order.get(r["grade"], 9), r["case_id"])) + + for i, rec in enumerate(rows): + r = head + 1 + i + for c, (field, _, _, wrap) in enumerate(COLUMNS, start=1): + value = rec.get(field, "") + cell = ws.cell(row=r, column=c) + if field == "url" and value: + cell.value = "원문 링크" + cell.hyperlink = value + cell.font = LINK_FONT + cell.alignment = TOP_LEFT + cell.border = CELL_BORDER + continue + cell.value = value + _body(cell, wrap=wrap) + if field == "grade": + cell.alignment = CENTER + cell.font = Font(name="맑은 고딕", size=10, bold=True, color=INK) + if value in GRADE_FILL: + cell.fill = GRADE_FILL[value] + + last = head + len(rows) + ws.auto_filter.ref = f"A{head}:{get_column_letter(len(COLUMNS))}{last}" + ws.freeze_panes = ws.cell(row=head + 1, column=3) + ws.sheet_view.zoomScale = 90 + + +# --------------------------------------------------------------------------- +# 시트 2 — 요약·방법 +# --------------------------------------------------------------------------- + + +def sheet_summary(wb: Workbook, rows: list[dict]) -> None: + ws = wb.create_sheet("요약·방법") + _widths(ws, [30, 12, 78]) + r = _title_block( + ws, "요약과 선정 방법", + "선정 기준은 '자서전·출판물의 본문 표절 판단에 실제로 기준을 주는가' 하나다. " + "저작권 사건이라는 이유만으로는 넣지 않았다.", + width_cols=3, + ) + + ws.cell(row=r, column=1, value="■ 검토 단계별 건수").font = SECTION_FONT + r += 1 + _header_row(ws, r, ["단계", "건수", "비고"]) + r += 1 + for name, n, note in FUNNEL: + ws.cell(row=r, column=1, value=name) + ws.cell(row=r, column=2, value=n) + ws.cell(row=r, column=3, value=note) + for c in (1, 2, 3): + _body(ws.cell(row=r, column=c)) + ws.cell(row=r, column=2).alignment = CENTER + if name in ("운영 적재본", "최종 선정"): + for c in (1, 2, 3): + ws.cell(row=r, column=c).font = Font( + name="맑은 고딕", size=10, bold=True, color=INK + ) + r += 1 + + r += 1 + ws.cell(row=r, column=1, value="■ 등급 정의").font = SECTION_FONT + r += 1 + _header_row(ws, r, ["등급", "구분", "정의"]) + r += 1 + for grade, label, desc in GRADE_DEF: + ws.cell(row=r, column=1, value=grade).fill = GRADE_FILL[grade] + ws.cell(row=r, column=2, value=label) + ws.cell(row=r, column=3, value=desc) + for c in (1, 2, 3): + _body(ws.cell(row=r, column=c)) + ws.cell(row=r, column=1).alignment = CENTER + r += 1 + + r += 1 + ws.cell(row=r, column=1, value="■ 본 과제에 가장 직접적인 3건").font = SECTION_FONT + r += 1 + _header_row(ws, r, ["사건번호", "법원", "의의"]) + r += 1 + for case_id, court, why in KEY_THREE: + ws.cell(row=r, column=1, value=case_id) + ws.cell(row=r, column=2, value=court) + ws.cell(row=r, column=3, value=why) + for c in (1, 2, 3): + _body(ws.cell(row=r, column=c)) + r += 1 + + r += 2 + note = ws.cell(row=r, column=1, value=DISCLAIMER) + note.font = NOTE_FONT + note.alignment = TOP_WRAP + ws.merge_cells(start_row=r, start_column=1, end_row=r, end_column=3) + ws.row_dimensions[r].height = 44 + + +# --------------------------------------------------------------------------- +# 시트 3 — 제외 사유 +# --------------------------------------------------------------------------- + + +def sheet_excluded(wb: Workbook) -> None: + ws = wb.create_sheet("제외 사유") + _widths(ws, [30, 34, 76]) + r = _title_block( + ws, "제외한 판례와 사유", + "무리해서 목록을 채우지 않았다. 무엇을 왜 뺐는지 남겨 두어야 이후 상담에서 " + "범위를 다시 넓힐지 판단할 수 있다.", + width_cols=3, + ) + + ws.cell(row=r, column=1, value="■ 데이터 수집 단계에서 제외").font = SECTION_FONT + r += 1 + _header_row(ws, r, ["사유", "건수", "설명"]) + r += 1 + for reason, n, desc in EXCLUDED_COLLECTION: + ws.cell(row=r, column=1, value=reason) + ws.cell(row=r, column=2, value=n) + ws.cell(row=r, column=3, value=desc) + for c in (1, 2, 3): + _body(ws.cell(row=r, column=c)) + ws.cell(row=r, column=2).alignment = CENTER + r += 1 + + r += 1 + ws.cell(row=r, column=1, value="■ 적재본에는 있으나 리스트업에서 뺀 유형").font = SECTION_FONT + r += 1 + _header_row(ws, r, ["유형", "대표 사건번호", "제외 사유"]) + r += 1 + for kind, cases, reason in EXCLUDED_TYPES: + ws.cell(row=r, column=1, value=kind) + ws.cell(row=r, column=2, value=cases) + ws.cell(row=r, column=3, value=reason) + for c in (1, 2, 3): + _body(ws.cell(row=r, column=c)) + r += 1 + + +# --------------------------------------------------------------------------- +# 시트 4 — 데이터 공백 +# --------------------------------------------------------------------------- + + +def sheet_gaps(wb: Workbook) -> None: + ws = wb.create_sheet("데이터 공백") + _widths(ws, [6, 40, 58, 60]) + r = _title_block( + ws, "확인된 데이터 공백 — 상담 시 짚어야 할 항목", + "이 표의 항목은 아직 해소되지 않았다. 전문가 상담 전에 원문 확보가 필요하거나, " + "상담 질의로 돌려야 하는 건이다.", + width_cols=4, + ) + _header_row(ws, r, ["#", "항목", "해당 사건", "설명"]) + r += 1 + for i, (item, cases, desc) in enumerate(GAPS, start=1): + ws.cell(row=r, column=1, value=i) + ws.cell(row=r, column=2, value=item) + ws.cell(row=r, column=3, value=cases) + ws.cell(row=r, column=4, value=desc) + for c in range(1, 5): + _body(ws.cell(row=r, column=c)) + ws.cell(row=r, column=1).alignment = CENTER + ws.cell(row=r, column=2).font = Font(name="맑은 고딕", size=10, bold=True, color=INK) + r += 1 + + r += 1 + warn = ws.cell( + row=r, column=2, + value="주의: 2012나17150(선덕여왕 항소심)은 1심과 결론이 뒤집힌 사례이며 " + "상고심 판단이 적재본에 없다. 항소심 결론을 확정 법리로 인용하지 말 것.", + ) + warn.font = Font(name="맑은 고딕", size=10, bold=True, color="B03A22") + warn.alignment = TOP_WRAP + ws.merge_cells(start_row=r, start_column=2, end_row=r, end_column=4) + ws.row_dimensions[r].height = 32 + + +# --------------------------------------------------------------------------- +# 시트 5 — 상담 질의 +# --------------------------------------------------------------------------- + + +def sheet_questions(wb: Workbook) -> None: + ws = wb.create_sheet("상담 질의") + _widths(ws, [6, 104]) + r = _title_block( + ws, "전문가 상담 시 질의 제안", + "자서전 직접 판례가 없다는 점이 확인된 이상, 인접 유형 법리의 유추가 " + "타당한지가 상담의 핵심이 되어야 한다.", + width_cols=2, + ) + _header_row(ws, r, ["#", "질의"]) + r += 1 + for i, q in enumerate(QUESTIONS, start=1): + ws.cell(row=r, column=1, value=i) + ws.cell(row=r, column=2, value=q) + for c in (1, 2): + _body(ws.cell(row=r, column=c)) + ws.cell(row=r, column=1).alignment = CENTER + ws.row_dimensions[r].height = 34 + r += 1 + + +# --------------------------------------------------------------------------- + + +def load_rows(path: Path) -> list[dict]: + if not path.exists(): + raise SystemExit( + f"{path} 가 없습니다. 먼저 scripts/build_precedent_listup.py 로 CSV 를 만드세요." + ) + with io.open(path, encoding="utf-8-sig", newline="") as fh: + rows = list(csv.DictReader(fh)) + if not rows: + raise SystemExit(f"{path} 에 데이터 행이 없습니다.") + return rows + + +def main() -> int: + ap = argparse.ArgumentParser( + description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter + ) + ap.add_argument("--csv", type=Path, + default=ROOT / "data/precedents/precedent_listup.csv") + ap.add_argument("--out", type=Path, default=ROOT / "docs/판례_리스트업.xlsx") + args = ap.parse_args() + + rows = load_rows(args.csv) + + wb = Workbook() + wb.remove(wb.active) # 기본 시트 제거 + sheet_list(wb, rows) + sheet_summary(wb, rows) + sheet_excluded(wb) + sheet_gaps(wb) + sheet_questions(wb) + + args.out.parent.mkdir(parents=True, exist_ok=True) + wb.save(args.out) + + counts = Counter(r["grade"] for r in rows) + print(f"생성: {args.out}") + print(f" 판례 {len(rows)}건 (A {counts['A']} / B {counts['B']} / C {counts['C']})") + print(f" 시트 {len(wb.sheetnames)}개: {', '.join(wb.sheetnames)}") + return 0 + + +if __name__ == "__main__": + sys.exit(main())