diff --git a/A00_Common/spreadsheet/spreadsheet_clipboard.ts b/A00_Common/spreadsheet/spreadsheet_clipboard.ts index 06c25067..45c514d4 100644 --- a/A00_Common/spreadsheet/spreadsheet_clipboard.ts +++ b/A00_Common/spreadsheet/spreadsheet_clipboard.ts @@ -254,9 +254,16 @@ function cssColorToHex(v: string | undefined): string | undefined { return undefined; } -/** 엑셀 `mso-number-format:"\#\,\#\#0\.00"` — 따옴표 떼고 `\x` 이스케이프 풀기. */ +/** 엑셀 `mso-number-format:"\#\,\#\#0\.00"` — 따옴표 떼고 `\x` 이스케이프 풀기(`\0022` 처럼 진짜 + * CSS 유니코드 이스케이프(`\` + 16진 1~6 자리, 회계 형식 글자 구역 따옴표 `"` 를 이렇게 실음)도 + * 먼저 풀지 않으면 따옴표 대신 글자 "0022" 가 그대로 남아 형식이 깨짐 — sub5 numfmt 가 받는 + * 형식 코드에는 이 CSS 껍데기가 없어야 함). */ function unescapeMsoNumFmt(v: string): string { - return v.replace(/^"|"$/g, "").replace(/\\(.)/g, "$1"); + return v + .replace(/^"|"$/g, "") + .replace(/\\([0-9a-fA-F]{1,6}) ?|\\(.)/g, (_, hex, ch) => + hex !== undefined ? String.fromCodePoint(parseInt(hex, 16)) : ch, + ); } /** pt 굵기 → 우리 선 종류(엑셀 내보내기 흔한 값 기준 — hairline ≈ .5pt 이하 · thin ≈ 1pt · medium ≈