dochan (독한)
독한 native 문서 파서 — AI/LLM 최적 Markdown 변환
The toughest Korean document parser. HWP/HWPX/Office/PDF → Markdown, JSON, Plain Text.
Current stable version: 1.4.0
What is dochan?
dochan(독한)은 한글(HWP/HWPX)과 Office 문서를 native로 파싱하여 AI/LLM이 바로 사용할 수 있는 Markdown으로 변환하는 Python 파서입니다.
doc(문서) +한(韓, 한국) = dochan — "독한 파서"라는 더블 미닝- HWP 5.0 바이너리 + HWPX(OWPML) XML + Office OOXML/legacy binary + PDF(텍스트·표·읽기 순서) 네이티브 지원
- 동일 문서 HWP/HWPX/PDF 80쌍과 공개 HWP/HWPX 7,188개 회귀 코퍼스로 검증(2026-08 기준), 공개가능한 문서로 계속 학습시켜 개선할 예정
- 공개 OOXML fixture 50개의 고정 SHA-256 corpus와 형식별 회귀 테스트로 지속 검증
from dochan import Dochan
doc = Dochan("공문서.hwp")
print(doc.to_markdown())
Features
| 기능 | 설명 |
|---|---|
| HWP + HWPX + Office + PDF | HWP/HWPX, Office OOXML(.docx/.pptx/.xlsx), legacy Office(.doc/.ppt/.xls), PDF(.pdf)를 native parser로 파싱 |
| PDF 텍스트·표 추출 | CTM(그래픽 상태) 기반 좌표 레이아웃으로 문단·읽기 순서를 복원하고, 벡터 괘선으로 표(병합 셀 포함)를 재구성. 페이지 번호 provenance, 한글 ToUnicode, 표준 암호화(빈 암호) 지원. 스캔 PDF 는 이미지 추출+OCR 로 처리 |
| Markdown 출력 | 제목, 표, 서식(bold/italic), 수식까지 AI가 바로 쓸 수 있는 Markdown |
| 표 파싱 | 셀 병합, 중첩 표, 좌표 배치 지원 |
| 서식 보존 | CharShape 기반 bold/italic/글자크기 → TextRun 연결 |
| 제목 자동 감지 | Style 이름 + 글자 크기 기반 heading 레벨 판별 |
| 수식 LaTeX | HWP 수식 스크립트 → LaTeX 기본 변환 |
| JSON / Plain Text | Markdown 외 구조화 JSON, 플레인 텍스트 출력 |
| OCR (선택) | Tesseract 연동, 이미지 속 텍스트 추출 |
| CLI | dochan convert 문서.hwp 한 줄로 변환 |
| 배치 처리 | 디렉토리 단위 병렬 변환 |
| 보안 | Zip Bomb, XXE, Path Traversal, 메모리 폭발 방어 |
Installation
pip install dochan
OCR 기능이 필요한 경우(Python 3.10 이상):
pip install "dochan[ocr]"
brew install tesseract tesseract-lang # macOS
Quick Start
Python API
from dochan import Dochan
# HWP, HWPX, DOC, PPT, XLS, DOCX, PPTX, XLSX, PDF
doc = Dochan("보고서.hwp")
# AI/LLM용 Markdown
markdown = doc.to_markdown()
# 구조화 JSON
json_str = doc.to_json()
# 플레인 텍스트
text = doc.to_plain_text()
# 요소별 접근
for table in doc.find_all('table'):
print(f"표: {table.row_count}행 x {table.col_count}열")
for eq in doc.find_all('equation'):
print(f"수식: {eq.latex}")
# 메타데이터
print(doc.metadata)
CLI
# Markdown 변환 (stdout)
dochan convert 문서.hwp
# 파일로 저장
dochan convert 문서.hwp -o output.md
# JSON 출력
dochan convert 문서.hwpx --format json
# Word DOCX 변환
dochan convert 문서.docx
# Legacy Word DOC 변환
dochan convert 문서.doc
# PowerPoint PPTX 변환
dochan convert 발표.pptx
# Legacy PowerPoint PPT 변환
dochan convert 발표.ppt
# Excel XLSX 변환
dochan convert 표.xlsx
# Legacy Excel XLS 변환
dochan convert 표.xls
# PDF 텍스트 추출
dochan convert 문서.pdf
# 디렉토리 일괄 변환
dochan batch input_dir/ output_dir/ --format markdown --workers 4
# 문서 정보
dochan info 문서.hwp
OCR (이미지 속 텍스트 추출)
doc = Dochan("이미지포함문서.hwpx", ocr=True)
print(doc.to_markdown()) # 이미지 속 텍스트도 포함
Output Examples
Input: 한글 공문서 (.hwp)
Output: Markdown
# **사내 규정집**
| 연번 | 내용 | 일자 |
| --- | --- | --- |
| 1 | 제정 | 2020. 3. 1. |
| 2 | 개정 | 2024. 9.15. |
### **제1장 총칙**
**제1조(목적)** 이 규정은 회사 직원의 복무에 관한 사항을 정함을
목적으로 한다.
Supported Elements
| 요소 | HWP | HWPX | DOC | PPT | XLS | DOCX | PPTX | XLSX | |
|---|---|---|---|---|---|---|---|---|---|
| 텍스트 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| 표 (단순) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| 표 (셀 병합) | ✅ | ✅ | ⬜ | ⬜ | ✅ | ✅ | ✅ | ✅ | ✅ |
| 표 (중첩 텍스트) | ✅ | ✅ | ⬜ | ⬜ | — | ✅ | ⬜ | — | — |
| 서식 (bold/italic) | ✅ | ✅ | ⬜ | ⬜ | ✅ | ✅ | ✅ | ✅ | ✅ |
| 제목 감지 | ✅ | ✅ | ✅ | ✅ | — | ✅ | ✅ | — | ✅ |
| 스타일 상속 | ⬜ | ⬜ | ⬜ | — | — | ✅ | — | — | — |
| 수식 | ✅ | ✅ | ⬜ | ⬜ | ⬜ | ✅ | ⬜ | ✅ | ⬜ |
| 공유 수식 | — | — | — | — | ✅ | — | — | ✅ | — |
| 이미지 참조 | ✅ | ✅ | ⬜ | ⬜ | ⬜ | ✅ | ✅ | ✅ | ✅ |
| 이미지 대체 텍스트 | ✅ | ✅ | ⬜ | ⬜ | — | ✅ | ✅ | — | — |
| 표/그림 캡션 | ✅ | ✅ | ⬜ | ⬜ | — | ⬜ | ⬜ | — | — |
| 이미지 OCR | ✅ | ✅ | ⬜ | ⬜ | ⬜ | ✅ | ✅ | ✅ | ✅ |
| 머리글/바닥글 | ✅ | ✅ | ⬜ | — | — | ✅ | — | — | ⬜ |
| 각주/미주 | ✅ | ✅ | ⬜ | — | — | ✅ | — | — | ⬜ |
| 주석/코멘트 | ✅ | ✅ | ⬜ | — | — | ✅ | — | ✅ | ⬜ |
| 변경 추적 | ⬜ | ⬜ | ⬜ | — | — | ✅ | — | — | — |
| 컨트롤/스마트 태그 텍스트 | ⬜ | ⬜ | ⬜ | — | — | ✅ | — | — | — |
| 텍스트박스/도형 텍스트 | ✅ | ✅ | ⬜ | ⬜ | — | ✅ | ✅ | — | — |
| 필드 결과 텍스트 | ✅ | ✅ | ✅ | ✅ | — | ✅ | — | — | — |
| 여러 슬라이드 | — | — | — | ✅ | — | — | ✅ | — | — |
| 레이아웃 상속 텍스트 | — | — | — | ⬜ | — | — | ✅ | — | — |
| 발표자 노트 | — | — | — | ⬜ | — | — | ✅ | — | — |
| 읽기 순서 | ✅ | ✅ | ⬜ | ⬜ | — | ⬜ | ✅ | — | ✅ |
| 그룹 도형 | — | — | — | ⬜ | — | — | ✅ | — | — |
| 페이지 번호 provenance | — | — | — | — | — | — | — | — | ✅ |
| 현대 PDF(1.5+) xref/객체 스트림 | — | — | — | — | — | — | — | — | ✅ |
| 표준 암호화(RC4/AES, 빈 암호) | — | — | — | — | — | — | — | — | ✅ |
| 차트 제목/데이터 | — | — | ⬜ | ⬜ | ⬜ | ⬜ | ✅ | ⬜ | — |
| 여러 시트 | — | — | — | — | ✅ | — | — | ✅ | — |
| sharedStrings | — | — | — | — | ✅ | — | — | ✅ | — |
| Boolean/error/formula cached value | — | — | — | — | ✅ | — | — | ✅ | — |
| rich text 문자열 | — | — | — | — | ⬜ | — | — | ✅ | — |
| 날짜/숫자 서식 | — | — | — | — | ✅ | — | — | ✅ | — |
| 빈 행/열 좌표 보존 | — | — | ⬜ | — | ✅ | — | — | ✅ | — |
| 하이퍼링크 | ✅ | ✅ | ⬜ | ⬜ | ✅ | ✅ | ✅ | ✅ | ⬜ |
| 하이퍼링크 URL | ✅ | ✅ | ⬜ | ⬜ | ✅ | ✅ | ✅ | ✅ | ✅ |
| 내부 하이퍼링크 | ✅ | ✅ | ⬜ | ⬜ | ⬜ | ✅ | ✅ | ✅ | ⬜ |
| 내부 북마크 | ✅ | ✅ | ⬜ | — | — | ✅ | — | — | ✅ |
| 암호화 문서 | ⬜ | — | ⬜ | ⬜ | ⬜ | ⬜ | ⬜ | ⬜ | ✅ |
✅ 지원 ⬜ 미지원 — 해당 없음
Legacy Office(.doc/.ppt/.xls)는 현재 OLE/BIFF native 기반의 기초 구조 복원 단계입니다.
.doc는 WordDocument FIB 텍스트 범위, 0Table/1Table CLX piece table, compressed piece flag, UTF-16/cp1252 compressed 본문 선택, legacy layout 문자와 soft line/page break 정규화, quoted/unquoted/internal HYPERLINK field 표시 텍스트/URL 및 일반 field 결과 텍스트, single-byte smart quote/dash 문장부호, legacy bullet/numbered/parenthesized numbered/alpha/roman outline list marker, legacy checkbox/checklist marker, underline-style heading, 한국어 제목/소제목 label, section break, 명시적 heading/list/table/key-value form 및 전각 콜론 key-value 신호, Word cell marker 및 tab/pipe-delimited/Markdown-style pipe/고정폭 공백·전각 공백 정렬 표 구조를 복원하고,.ppt는 slide/notes/comments container, 중첩 notes/comments container의 직전 슬라이드 연결, quoted/unquoted/internal HYPERLINK field 표시 텍스트/URL 및 일반 field 결과 텍스트, cp1252 byte text 문장부호, legacy layout 문자와 soft line/page break 정규화, legacy bullet/numbered/parenthesized numbered/alpha/roman outline list marker, legacy checkbox/checklist marker, underline-style heading, 한국어 제목/소제목 label, tab/pipe-delimited/Markdown-style pipe/고정폭 공백·전각 공백 정렬 표와 key-value form/전각 콜론 key-value 구조, 반복 텍스트 라인, TextHeaderAtom title/center-title/body 신호를 반영하며,.xls는 BIFF sheet/table/merged-cell/cell 타입, HEADER/FOOTER 시트 문단과 제어 코드 정규화, cp1252 compressed 문자열 문장부호, BIFF2/3/4 LABEL 셀, BIFF INTEGER 정수 셀, legacy NUMBER 숫자 셀, legacy BOOLERR boolean/error 셀, legacy BLANK 빈 좌표, rich-text/SST CONTINUE shared string, RSTRING rich-text label 셀, 문자열 중간에서 끊긴 SST CONTINUE, HLINK URL, NOTE 코멘트 작성자, DIMENSION used-range, ROW/COLINFO 행·열 범위, BLANK/MULBLANK 빈 좌표, RK/MULRK 압축 숫자, FORMAT/XF 기반 날짜·퍼센트·통화 서식, 이름 정의 대상 문단, RPN 수식·범위·절대/혼합/다른 시트 참조/이름 정의 참조 flag·operand class variant·문자열/boolean/error literal·단항/퍼센트/괄호·지수·IF/AND/OR/NOT/COUNT/ROUND/TRUE/FALSE/가변/다중 인자 고정 함수·비교·문자열 결합 토큰, FORMULA cached boolean/표준 error/blank 결과, SHRFMLA 공유 수식 템플릿/상대 참조 보정과 STRING/legacy STRING/legacy byte STRING 후속 레코드 기반 문자열 수식 결과를 복원합니다.
Architecture
dochan/
├── reader.py # 통합 진입점 (Dochan 클래스)
├── cli.py # CLI 도구
├── hwp/ # HWP 5.0 바이너리 파서
│ ├── header.py # FileHeader (256바이트)
│ ├── doc_info.py # DocInfo (서식/스타일)
│ ├── section.py # 섹션 (레코드 트리 → 모델)
│ └── records/ # 개별 레코드 파서
├── hwpx/ # HWPX (OWPML) XML 파서
│ └── parser.py
├── ooxml/ # Office Open XML native 파서
│ ├── package.py # 안전한 ZIP/XML 패키지 유틸
│ ├── docx.py # DOCX 문단/서식/표 파서
│ ├── pptx.py # PPTX 슬라이드/텍스트/표 파서
│ └── xlsx.py # XLSX workbook/sheet/cell 파서
├── office_binary/ # Legacy Office OLE native 파서
│ ├── structure.py # legacy 텍스트 heading/table/list 구조화
│ ├── doc.py # DOC WordDocument 텍스트/기초 구조 파서
│ ├── ppt.py # PPT slide/text/기초 구조 파서
│ └── xls.py # XLS BIFF workbook/sheet/cell 파서
├── pdf/ # 네이티브 PDF 파서
│ ├── objects.py # 객체 문법 파서
│ ├── filters.py # Flate/ASCIIHex/ASCII85 + PNG predictor
│ ├── structure.py # xref/트레일러/페이지 트리/객체 스트림
│ ├── crypto.py # 표준 보안 핸들러(RC4/AES)
│ ├── cmap.py # ToUnicode CMap
│ ├── widths.py # 글리프 폭 맵
│ ├── content.py # 콘텐츠 스트림 해석(CTM·텍스트 좌표)
│ ├── paths.py # 경로 연산자 → 괘선 수집
│ ├── tables.py # 괘선 격자 → 표/병합 셀
│ ├── layout.py # 줄 → 문단 병합
│ ├── images.py # 이미지 XObject 추출
│ └── reader.py # PDFReader (페이지 → Document)
├── model/ # Document 모델
│ ├── document.py # Document, Section, Paragraph
│ ├── table.py # Table, Cell
│ └── equation.py # Equation (LaTeX 변환)
├── output/ # 출력 포맷
│ ├── markdown.py # Markdown (AI/LLM 최적)
│ ├── json_out.py # 구조화 JSON
│ └── plain_text.py # 플레인 텍스트
└── utils/ # 유틸리티
├── ocr.py # Tesseract OCR
└── safe_decompress.py # Zip Bomb 방어
Security
dochan은 신뢰할 수 없는 문서도 안전하게 처리합니다:
- Zip Bomb 방어: raw zlib 출력 200MB, OOXML/HWPX XML part 32MB, 일반 part 100MB, archive 합계 512MB 상한
- XXE 차단: XML 외부 엔티티 해석 비활성화
- Path Traversal 방지: 배치 처리 시 경로 탈출 차단
- 메모리 제한: HWP·HWPX·DOCX·XLSX·XLS·PDF 문서당 표 셀 20만 개, HWP·DOCX 일반 구조 깊이 64, HWP·DOCX 표 깊이 32, PPTX 그룹 깊이 64 상한. PDF 는 페이지 콘텐츠 합계 64MB, 괘선 2만 개, 괘선 교차 검사 200만 회, 스트림 해제 200MB 추가 상한
- 입력 검증: FileHeader/스트림명/OOXML 패키지명/바이너리 바운드 체크
Contributing
기여를 환영합니다! Issues, Pull Requests 모두 열려 있습니다.
# 개발 환경 설정
git clone https://github.com/illuwa/dochan.git
cd dochan
python -m pip install "uv==0.12.3"
uv sync --locked --extra dev
uv run --locked --extra dev ruff check dochan scripts tests
uv run --locked --extra dev python -m pytest tests/
Acknowledgments
kordoc를 보고 자극받아 만들었습니다.
dochan은 다음 프로젝트와 자료를 기반으로 개발되었습니다:
스펙 참조
- 한글과컴퓨터 — HWP 문서 파일 형식 5.0 공개 스펙 (revision 1.3, 2018)
- OWPML (KS X 6101:2011) — HWPX 국가 표준
오픈소스
- olefile — OLE2 파일 파싱 (Philippe Lagadec, BSD)
- lxml — XML 파싱 (BSD)
- pdfplumber — 품질 검증용 PDF 추출 (MIT)
- Tesseract OCR — 이미지 텍스트 추출 (Apache 2.0)
선행 연구
License
본 소프트웨어는 한글과컴퓨터의 HWP 문서 파일(.hwp) 공개 문서를 참고하여 개발되었습니다. 자세한 내용은 NOTICE 파일을 참조하세요.
Metadata
Release files for dochan 1.4.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| dochan-1.4.0.tar.gz | 196.3 kB | Without provenance | Details for dochan-1.4.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| dochan-1.4.0-py3-none-any.whl | Python 3 | none | any | Details for dochan-1.4.0-py3-none-any.whl |
Total release size: 417.2 kB
Release files / dochan-1.4.0.tar.gz
| Download URL | dochan-1.4.0.tar.gz |
|---|---|
| Size | 196.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
7a3df61c2ec8d6e91589737085b735322a820f006577751a7117282794431002
|
|
BLAKE2b-256 checksum How to use checksums |
d4a80f036be83716b72f782e4c9e3c58ab414fcd4fd979dcfe3b8b40ff9b45be
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Release files / dochan-1.4.0-py3-none-any.whl
| Download URL | dochan-1.4.0-py3-none-any.whl |
|---|---|
| Size | 220.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
fcde3a647519c60361392fc73623187e11ee3969c4640c8d66d792b1e6a6e09f
|
|
BLAKE2b-256 checksum How to use checksums |
5992937d1502c090b88eb3193fe6deaac82da1c260f4d3bde4087d2a57112a8d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Security for dochan 1.4.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.