AI 해결 노트 · 2026-09-18 · 실측 2026-09-18
한글 양식 빈칸 채우는 세 가지 — 표 칸·누름틀·찾아 바꾸기를 같은 서식으로 대조
한 줄로
표로 된 신청서 더미를 직접 만들어 같은 값을 세 가지로 넣어 봤습니다. 표 칸에 대고 치기, 누름틀에 값 넣기, [성명] 같은 자리표시자를 찾아 바꾸기입니다. 나온 PDF 세 장은 150dpi로 그려 해시를 내 보니 화소 한 점까지 같았습니다. 갈리는 건 결과가 아니라 틀렸을 때입니다. 없는 누름틀 이름을 부르면 오류도 없이 문서가 그대로였고, 없는 자리표시자를 찾으면 False가 돌아왔고, 표 칸에서 커서를 한 칸 잘못 옮기면 값이 라벨 칸에 붙어 버렸습니다.
이런 분께
사내 신청서·확인서 같은 한글 양식에 이름만 바꿔 여러 장을 만들어야 하는 분입니다. 어느 방식으로 양식을 짜 둬야 나중에 덜 고생하는지가 궁금한 경우입니다.
실측 환경
| 항목 | 값 |
|---|---|
| OS | Windows 11 Home (10.0.26200) |
| 한글 | 한글 Office 2022, 버전 문자열 12, 0, 0, 4605 |
| PDF 읽기 | PyMuPDF 1.28.0 (MuPDF 1.29.0), Python 3.12.10 |
| 더미 양식 | 6줄 2칸 표. PDF에서 잰 칸 너비는 왼쪽 78.5mm, 오른쪽 78.6mm, 줄 높이 약 11mm |
| 채운 값 | 홍길동 / 010-0000-0000 / 총무팀 / 2026-09-18 / 문서 작성 기초 / 신청 사유 81자 |
| 만든 곳 | C:\Users\User\AppData\Local\Temp\office_KO3 |
양식과 값은 전부 지어낸 것입니다. 회사 서식이나 남의 신청서는 쓰지 않았습니다.
아래 숫자는 한글에서 같은 기능을 자동화(한글 COM)로 불러 얻은 것입니다. 메뉴를 눌러 보고 찍은 화면은 이 글에 없습니다.
더미 양식
빈칸이 오른쪽에 있는 흔한 꼴로 만들었습니다.

같은 표를 세 벌 만들었습니다. 오른쪽 칸을 그냥 비워 둔 것(A), 누름틀을 하나씩 심어 둔 것(B), [성명] 같은 자리표시자를 적어 둔 것(C)입니다. 파일 크기가 셋 다 다릅니다.
SaveAs KO3_55_form_A.hwp -> True (18944 바이트) ← 빈칸
SaveAs KO3_55_form_B.hwp -> True (22016 바이트) ← 누름틀 6개
SaveAs KO3_55_form_C.hwp -> True (19968 바이트) ← [성명] 자리표시자
누름틀 목록 = '성명\x02연락처\x02소속\x02신청일\x02과정명\x02신청사유'누름틀을 심은 B가 빈칸 양식 A보다 3,072바이트 큽니다. 무엇이 그만큼을 차지하는지는 뜯어보지 않았습니다.
세 가지로 채운 결과
같은 값을 세 방식으로 넣고 각각 PDF로 저장했습니다.

눈으로는 구별이 안 됩니다. 그래서 세 PDF를 150dpi로 그려 화소 덩어리째 해시를 냈습니다.
① 표 칸 직접 입력 1240x1753 화소 sha256[:16]=11066f40de6a401c
② 누름틀에 값 넣기 1240x1753 화소 sha256[:16]=11066f40de6a401c
③ 찾아 바꾸기 1240x1753 화소 sha256[:16]=11066f40de6a401c
세 해시가 모두 같은가 = True글꼴도 셋 다 INPILL+HCRBatang 한 벌, 쪽 수도 1쪽, PDF에서 뽑히는 글자도 186자로 같습니다. 파일 크기만 22,947 / 22,949 / 22,947바이트로 두 바이트 차이가 났습니다.
받는 사람이 보는 결과물만 놓고 보면 세 방식은 구별할 게 없습니다.
안 채운 채로 넘기면 — 여기서 갈린다
값을 하나도 넣지 않은 채 세 양식을 그대로 PDF로 저장해 봤습니다.

누름틀 양식은 문서 글자를 읽어 보면 "성명 입력" 같은 안내문이 나옵니다.
B_누름틀 본문글자='… / 성명 / 성명 입력 / 연락처 / 연락처 입력 / 소속 / 소속 입력 / …'그런데 그 상태로 PDF를 만들면 안내문은 따라가지 않습니다.
A_빈칸 PDF에서 뽑은 글자: … 성명 / 연락처 / 소속 / 신청일 / 과정명 / 신청 사유
B_누름틀 PDF에서 뽑은 글자: … 성명 / 연락처 / 소속 / 신청일 / 과정명 / 신청 사유
C_자리표시자 PDF에서 뽑은 글자: … 성명 / [성명] / 연락처 / [연락처] / 소속 / [소속] / …빈 양식 PDF의 크기도 A와 B가 16,198바이트로 같았고, C만 16,423바이트였습니다. 누름틀 안내문은 이번 PDF에서 뽑은 글자에 없었고, 자리표시자는 그냥 글자라서 빠뜨리면 [연락처]가 적힌 채로 상대에게 갑니다.
이게 두 방식의 진짜 차이입니다. 자리표시자 방식은 안 채운 칸이 눈에 확 띄고, 누름틀 방식은 안 채운 칸이 PDF에서 그냥 빈칸이 됩니다. 종이에 인쇄했을 때도 같은지는 확인하지 않았습니다.
이름만 바꿔 세 장
같은 양식을 열어 여섯 칸을 채워 세 장씩 뽑았습니다. 시간은 양식 파일을 여는 호출부터 PDF 저장이 끝날 때까지입니다.
| 방식 | 1장 | 2장 | 3장 | 합계 | 세 장 모두 값이 제자리에 |
|---|---|---|---|---|---|
| ① 표 칸에 직접 입력 | 1.42초 | 0.50초 | 0.51초 | 2.42초 | 들어감 |
| ② 누름틀에 값 넣기 | 0.27초 | 0.33초 | 0.38초 | 0.99초 | 들어감 |
| ③ 찾아 바꾸기 | 0.60초 | 0.40초 | 0.46초 | 1.46초 | 들어감 |
①의 첫 장만 1.42초로, 둘째·셋째의 0.50초·0.51초보다 오래 걸렸습니다. 왜 첫 장만 그런지는 재지 않았습니다. 이건 자동화로 돌렸을 때의 시간이고, 사람이 손으로 칠 때의 시간은 아닙니다.
세 방식 모두 세 장이 다 1쪽으로 나왔고, 이름과 소속이 PDF에서 빠짐없이 검색됐습니다.
① 1장:O/O 쪽수1 2장:O/O 쪽수1 3장:O/O 쪽수1
② 1장:O/O 쪽수1 2장:O/O 쪽수1 3장:O/O 쪽수1
③ 1장:O/O 쪽수1 2장:O/O 쪽수1 3장:O/O 쪽수1틀렸을 때 무엇이 남는가
세 방식에 흔한 실수를 하나씩 넣어 봤습니다.
누름틀 이름을 잘못 부르면 — 실제 이름은 성명인데 이름으로 값을 넣어 봤습니다.
PutFieldText('이름') 반환 = None | 예외 없음
넣은 뒤 본문 = '… / 성명 / 성명 입력 / 연락처 / 연락처 입력 / …'
실제 누름틀 목록 = '성명\x02연락처\x02소속\x02신청일\x02과정명\x02신청사유'오류도 없고 되돌려 주는 값도 없습니다. 문서는 그대로입니다. 넣었다고 생각하고 그냥 저장하면 빈칸인 채로 나갑니다.
찾아 바꾸기 이름을 틀리면 — 없는 [이름]을 찾게 하면 False가 돌아옵니다.
AllReplace('[이름]'->'홍길동') 반환 = False
AllReplace('[성명]'->'홍길동') 반환 = True적어도 못 찾았다는 사실은 알려 줍니다. 그리고 안 바뀐 칸은 [연락처]처럼 종이에 그대로 남으니 눈으로도 잡힙니다.
표 칸에 직접 칠 때 커서가 한 칸 밀리면 — 값이 라벨 칸으로 들어갑니다.

본문 = '… / 홍길동성명 / / 010-0000-0000연락처 / / 총무팀소속 / / …'홍길동성명처럼 라벨에 값이 붙고 오른쪽 칸은 비었습니다. 이건 한눈에 보이니 오히려 나은 편입니다.
긴 값을 넣으면 칸이 어떻게 되나
누름틀 양식의 신청 사유 칸에 81자와 567자를 각각 넣어 봤습니다.

PDF에서 가로줄 사이를 재 보면 이렇습니다.
81자 : 칸 높이(pt) = [31.1, 31.2, 31.0, 31.2, 31.2, 60.7] 표 아래끝 348.9pt
567자 : 칸 높이(pt) = [31.1, 31.2, 31.0, 31.2, 31.2, 364.4] 표 아래끝 652.6pt앞 다섯 줄은 31pt(약 11mm)로 그대로인데 마지막 줄만 60.7pt(약 21mm), 567자에서는 364.4pt(약 129mm)까지 늘었습니다. 표 아래끝도 348.9pt에서 652.6pt로 내려갔고, "위 내용이 사실임을 확인합니다."라는 문장은 두 경우 모두 표 아래쪽에 있었습니다.
81자를 넣은 결과에서는 칸을 넘친 글자가 한 조각도 없었습니다. 글자 조각마다 자리를 재 표 테두리와 견줘 봤습니다.
가로줄 y = [132.5, 163.6, 194.8, 225.8, 257.0, 288.2, 348.9]
세로줄 x = [86.5, 309.1, 531.8]
칸을 넘친 글자 조각 수 = 0이번 양식에서는 사유가 길어지자 칸이 커지고 표 아래끝이 내려갔습니다. 567자 쪽에서도 같은 넘침 검사를 돌리지는 않았습니다. 한 장에 딱 맞춰 만든 서식이라면 사유란에 긴 글을 넣는 순간 아래가 밀려 나가니, 값을 넣은 뒤 쪽 수를 한 번 세 보시는 게 안전합니다.
결과
| 보는 눈 | ① 표 칸 직접 입력 | ② 누름틀 | ③ 찾아 바꾸기 |
|---|---|---|---|
| 채운 뒤 PDF | 화소까지 같음 | 화소까지 같음 | 화소까지 같음 |
| 양식 파일 크기 | 18,944바이트 | 22,016바이트 | 19,968바이트 |
| 세 장 뽑는 데 | 2.42초 | 0.99초 | 1.46초 |
| 이번에 넣어 본 실수 | 커서 한 칸 밀림 → 라벨 칸에 값이 붙음 | 없는 이름 호출 → 예외 없이 문서 그대로 | 없는 자리표시자 → False 반환 |
| 안 채우고 보내면 | 빈칸 | 빈칸(안내문은 안 뽑힘) | [연락처] 가 찍힘 |
| 사유 81→567자 | 시험 안 함 | 마지막 칸 높이 60.7 → 364.4pt | 시험 안 함 |
실패한 것
- 표를 만들 때 칸 너비를 왼쪽 40mm, 오른쪽 110mm로 줬는데 들어가지 않았습니다. 빈 양식 PDF에서 세로줄을 재 보니 왼쪽 222.6pt(78.5mm), 오른쪽 222.7pt(78.6mm)로 거의 반반이었습니다. 이 글의 그림에서 라벨 칸이 넓어 보이는 것도 그래서입니다. 왜 안 먹었는지는 못 찾았습니다.
- 글자가 칸을 넘쳐 겹치는 장면을 만들려 했는데 만들지 못했습니다. 칸의 「줄 나눔」 값을 0·1·2로 바꿔 세 번 돌렸고 호출은 세 번 다
True를 돌려줬는데, 세 결과의 가로줄 위치가[132.5, 163.6, 194.8, 225.8, 257.0, 288.2, 348.9]로, 칸 높이가[31.1, 31.2, 31.0, 31.2, 31.2, 60.7]로 똑같이 나왔습니다. 설정이 닿지 않았는지, 닿았는데 결과가 같은 것인지는 가리지 못했습니다. - 찾아 바꾸기 설정에
AllReplace라는 항목이 있는 줄 알고 값을 넣다가 멈췄습니다. 그 이름은 없습니다.
ps.AllReplace = 1 -> AttributeError: … object has no attribute 'AllReplace'
있는 항목 = ['AllWordForms', 'AutoSpell', … 'ReplaceMode', 'ReplaceString', … 'WholeWordOnly']- 문서를 닫아 가며 돌리던 중 한글과 끊긴 적이 한 번 있었습니다(
RPC 서버를 사용할 수 없습니다). 같은 절차를 다시 밟았을 때는 나지 않았고, 대신 열린 문서가 하나뿐일 때 닫기를 불러도 문서 수가 1개 그대로였습니다. 끊긴 원인은 못 밝혔습니다.
확인하지 않은 것
- 한글 창을 띄워 메뉴를 눌러 보지 않았습니다. 누름틀을 넣는 메뉴 이름, 찾아 바꾸기 창의 생김새는 이 글에 없습니다. 여기 있는 것은 같은 기능을 자동화로 불러 나온 결과뿐입니다.
- 손으로 직접 쳤을 때 세 장에 몇 분이 걸리는지는 재지 않았습니다. 위 초 단위는 자동화가 낸 시간입니다.
- 칸을 합친 표, 여러 쪽짜리 양식, 도장란·서명란이 든 양식은 만들지 않았습니다. 6줄 2칸 한 장짜리만 봤습니다.
- 누름틀 안내문이 한글 화면에서 어떻게 보이는지는 그림으로 담지 않았습니다. 문서 글자를 읽어 안내문이 있다는 것만 확인했습니다.
- 인쇄기로 종이에 뽑았을 때도 안내문이 안 나오는지는 확인하지 않았습니다. PDF에서만 봤습니다.
- 긴 값 시험은 누름틀 양식으로만 했습니다. 나머지 두 방식으로도 같은지는 견주지 않았습니다.
- 다른 사람이 만든 양식에 누름틀이 이미 들어 있는 경우, 이름을 어떻게 알아내는지는 다루지 않았습니다.
- 한글 Office 2022 말고 다른 판에서는 돌려 보지 않았습니다.