File size: 2,613 Bytes
7f105c8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
"""슬롯 카드 헤더 분해 — todo.text → (헤더, 값) 페어.

강사님 처방 "슬롯 위주 가공" 대응:
  슬롯 카드 = 헤더(라벨) 굵게 + 값 행. 본 모듈이 헤더 추출 책임.

윤정님 split_sentences가 이미 헤더 단위로 todo를 분리해서 반환하므로
보통 todo.text 시작에 헤더 키워드가 옴. 또한 윤정님이 한글 프로 기호 +
표 구분자(`|`)를 정제하기로 합의됨 — 매칭 시 구분자는 옵셔널 처리.

매칭 실패 시 (None, 원문)을 반환해 호출부가 fallback("기타") 헤더로 처리.
"""
from __future__ import annotations

import re

# 가정통신문 표준 헤더 키워드.
# 윤정님 split_sentences 분리 룰의 키워드 + 갈산초/서대구초 케이스 보강.
# 긴 표현이 짧은 것에 흡수되지 않게 정렬은 길이 내림차순 (예: "기타 안내사항" 우선, "기타" 후순위).
HEADER_KEYWORDS: list[str] = [
    # 운영 계열
    "운영시간", "운영방법", "운영날짜", "운영기간", "운영장소",
    # 신청 계열
    "신청방법", "신청기간", "신청경로", "신청대상", "신청자격",
    # 접수/제출
    "접수기간", "접수방법", "접수처",
    "제출방법", "제출기한", "제출처",
    # 일정/장소
    "일시", "기간", "장소", "위치", "주소",
    # 대상/자격
    "대상", "자격", "참가대상",
    # 준비물/비용
    "준비물", "지참물", "준비사항",
    "비용", "회비", "참가비", "수강료", "급식비",
    # 안내/유의
    "기타 안내사항", "기타안내사항", "안내사항",
    "유의사항", "참고사항", "주의사항",
    # 문의
    "문의", "연락처", "문의처",
    # 기타 (가장 짧음, 마지막)
    "기타",
]

_HEADER_KEYWORDS_SORTED = sorted(HEADER_KEYWORDS, key=len, reverse=True)

# 줄 시작 + 헤더 키워드 + (선택적 `|`/`:`/`:` 구분자) + 값
# `|`는 윤정님이 정제하기 전엔 살아있을 수 있어 옵셔널 처리.
_HEADER_RE = re.compile(
    r"^\s*(?P<header>" + "|".join(re.escape(k) for k in _HEADER_KEYWORDS_SORTED) + r")"
    r"\s*[|::]?\s*"
    r"(?P<value>.+)$",
    re.DOTALL,
)


def split_header_value(text: str) -> tuple[str | None, str]:
    """todo.text → (헤더, 값) 페어.

    매칭 실패 시 (None, text.strip()) 반환 — 호출부에서 "기타" 같은 fallback 헤더 처리.
    """
    if not text or not text.strip():
        return None, ""
    m = _HEADER_RE.match(text.strip())
    if m:
        return m.group("header"), m.group("value").strip()
    return None, text.strip()