// 공용 유틸: HTML 엔티티 디코드, YYYYMMDD 날짜 파싱. const ENTITIES = { '&': '&', '<': '<', '>': '>', '"': '"', ''': "'", ''': "'", ' ': ' ', }; export function decodeEntities(s) { if (s == null) return null; return String(s) .replace(/&|<|>|"|'|'| /g, (m) => ENTITIES[m]) .replace(/&#(\d+);/g, (_, n) => String.fromCharCode(Number(n))) .trim(); } /** * 'YYYYMMDD' 또는 'YYYY-MM-DD' 를 Date 로. 형식 불일치면 null. */ export function parseYmd(s) { if (s == null) return null; const digits = String(s).replace(/[^0-9]/g, ''); if (digits.length !== 8) return null; const y = Number(digits.slice(0, 4)); const m = Number(digits.slice(4, 6)); const d = Number(digits.slice(6, 8)); if (m < 1 || m > 12 || d < 1 || d > 31) return null; return new Date(Date.UTC(y, m - 1, d)); } /** * 'YY-MM-DD' / 'YYYY-MM-DD' / 'YYYYMMDD' / 'YYMMDD' 를 Date 로. 불일치면 null. * 6자리는 20YY 로 간주한다. */ export function parseFlexibleDate(s) { if (s == null) return null; const d = String(s).replace(/[^0-9]/g, ''); let y; let mo; let day; if (d.length === 8) { y = Number(d.slice(0, 4)); mo = Number(d.slice(4, 6)); day = Number(d.slice(6, 8)); } else if (d.length === 6) { y = 2000 + Number(d.slice(0, 2)); mo = Number(d.slice(2, 4)); day = Number(d.slice(4, 6)); } else { return null; } if (mo < 1 || mo > 12 || day < 1 || day > 31) return null; return new Date(Date.UTC(y, mo - 1, day)); } export function nonEmpty(s) { if (s == null) return null; const t = String(s).trim(); return t === '' ? null : t; } /** * HTML 태그 제거 후 엔티티 디코드.
/

/ 는 줄바꿈으로. */ export function stripHtml(s) { if (s == null) return null; const text = String(s) .replace(/<\s*br\s*\/?>/gi, '\n') .replace(/<\/(p|div|li|tr|h[1-6])\s*>/gi, '\n') .replace(/<[^>]+>/g, '') .replace(/[ \t]+\n/g, '\n') .replace(/\n{3,}/g, '\n\n') .trim(); return decodeEntities(text); } /** * "A ~ B" 형식 기간 문자열을 {start, end} Date 로. 날짜형이 아니면 null. */ export function parsePeriodRange(s, sep = '~') { if (s == null) return { start: null, end: null }; const segs = String(s).split(sep).map((x) => x.trim()); return { start: parseFlexibleDate(segs[0]), end: parseFlexibleDate(segs[1] || segs[0]), }; }