EUC-KR
고친 사람 github-actions[bot]
EUC-KR 는 한글과 한자를 바이트로 바꿔 적는 한국어 전용 인코딩입니다. 영어 글자는 한 바이트로, 한글 한 글자는 두 바이트로 적습니다. 유니코드가 퍼지기 전에 한국에서 만든 문서와 프로그램이 이 방식을 썼습니다. 그때 적힌 바이트가 아직 옛 파일과 오래 굴러온 데이터베이스에 남아 있습니다.
쉽고 빠른 이해
EUC-KR 는 한글 한 글자를 두 바이트짜리 번호 하나로 바꾸는 규칙입니다. 글자 가 는 0xB0 0xA1 두 바이트가 됩니다. 글자를 바이트로 바꾸는 이런 규칙을 인코딩이라고 부릅니다.
컴퓨터가 주고받는 것은 바이트뿐입니다. 영어 글자에만 번호를 매긴 옛 인코딩에는 한글이 아예 없었습니다. 한글을 적으려면 그 인코딩이 안 쓰고 남긴 바이트 값에 한글을 따로 얹어야 했습니다. 얹는 방법을 정한 것이 EUC-KR 입니다.
어떻게 도나:
- 바이트 값이 127 이하면 영어 글자 하나로 읽습니다
- 그보다 크면 뒤의 바이트까지 둘을 묶습니다
- 묶은 두 바이트를 한글·한자 목록에서 찾아 글자 하나로 되돌립니다
대가는 둘입니다. 담을 수 있는 한글 음절이 2,350 자뿐이라 「뷁」처럼 드문 음절은 적지 못합니다. 그리고 바이트만 봐서는 이 파일이 EUC-KR 인지 알 수 없습니다. 다른 규칙으로 읽으면 글자가 깨집니다.
지금 새로 만드는 것은 유니코드 쪽 인코딩으로 적습니다. EUC-KR 는 옛 파일과 옛 데이터베이스를 넘겨받을 때 만납니다.
상세
EUC-KR 는 글자마다 정해진 번호를 바이트로 옮겨 적는 규칙입니다.
이름과 바탕이 된 글자 목록
EUC-KR 는 Extended Unix Code for Korean 의 줄임말입니다. Extended Unix Code 는 유닉스 계열 시스템에서 동아시아 글자를 다루려고 만든 인코딩 계열입니다. EUC-KR 는 그 계열을 한국어에 맞춰 세운 것입니다. 바탕에 깐 글자 목록은 KS X 1001(Korean Industrial Standards, 한국산업표준) 입니다.
어떤 글자를 담을지 정해 번호를 붙여 둔 목록을 문자 집합이라고 부릅니다. KS X 1001 이 바로 그 목록입니다. 한글 음절과 한자, 그리고 그리스 글자나 화살표 같은 특수 기호에 번호를 매겨 두었습니다.
번호를 실제 바이트로 옮겨 적는 규칙은 문자 인코딩이라고 따로 부릅니다. EUC-KR 가 그 인코딩 가운데 하나입니다. 목록이 번호를 정합니다. 인코딩은 그 번호를 바이트로 옮깁니다.
한국어를 위한 목록과 인코딩이 왜 따로 필요했는지는 ASCII(American Standard Code for Information Interchange) 를 보면 드러납니다. ASCII 는 영어 글자와 숫자, 기호에만 번호를 붙인 128칸짜리 목록입니다. 한글에 줄 번호가 없습니다. 한글을 적으려면 목록과 인코딩을 따로 만드는 수밖에 없었습니다.
같은 목록을 예전에는 KS C 5601 이라고 불렀습니다. 오래된 설정 파일과 라이브러리에는 그 이름이 아직 남아 있습니다. 가리키는 것은 같습니다.
지금까지 나온 네 이름이 어느 층에 서는지를 한 줄로 세우면 이렇습니다.
flowchart TD
G["글자 「가」"] --> KS["KS X 1001 — 담을 글자를 정하고 번호를 붙인다<br/>옛 이름 KS C 5601"]
KS --> N["코드 번호"]
N --> E["EUC-KR — 번호를 바이트로 옮긴다"]
E --> B["0xB0 0xA1"]
G -.-> A["ASCII — 영어·숫자·기호 128칸<br/>한글에 줄 번호가 없다"]
이 층 구분은 뒤 절에서도 계속 걸립니다. 2,350 자라는 한계는 위층인 목록의 것입니다. 뒤에 나올 확장이 EUC-KR 를 품는다는 것은 아래층인 인코딩의 이야기입니다.
바이트를 끊어 읽는 규칙
EUC-KR 바이트열에는 길이가 다른 두 조각이 섞여 있습니다. 한 바이트짜리 조각과 두 바이트짜리 조각입니다. 읽는 쪽은 바이트 값 하나만 보고 둘을 가릅니다.
값이 0x7F(십진 127) 이하인 구간은 ASCII 와 같은 번호를 씁니다. 그래서 영어와 숫자, 문장 부호로만 적은 파일은 EUC-KR 로 봐도 바이트가 한 개도 안 달라집니다.
값이 그보다 크면 한글이나 한자의 첫 바이트입니다. 첫 바이트 값이 어느 구간에 있느냐로 읽는 방법이 갈립니다.
| 첫 바이트 값 | 어떻게 읽나 | 글자 하나의 길이 |
|---|---|---|
0x00 ~ 0x7F |
그 바이트가 곧 ASCII 글자 | 1 바이트 |
0x80 ~ 0xA0 |
EUC-KR 가 안 쓰는 구간 | — |
0xA1 ~ 0xFE |
뒤 바이트와 묶는다 | 2 바이트 |
가운데 줄이 빈칸입니다. 0x80 부터 0xA0 까지는 EUC-KR 가 아무 글자도 안 붙이고 비워 둡니다. 뒤 절에 나올 확장이 이 빈 구간을 씁니다.
두 바이트짜리 글자는 뒤 바이트도 0xA1 부터 0xFE 사이입니다. 두 바이트 모두 0x7F 을 넘으므로 영어 글자나 쉼표, 줄바꿈과 값이 겹치지 않습니다.
덕분에 바이트만 훑는 프로그램이 한글 문서를 망가뜨리지 않습니다. 쉼표로 칸을 나누거나 줄바꿈으로 줄을 자르는 처리는 글자를 몰라도 안전합니다. 한글 바이트 안에 쉼표와 줄바꿈 값이 들어 있지 않기 때문입니다.
대신 글자 수와 바이트 수는 갈립니다. 한글 열 글자가 스무 바이트입니다. 바이트 수를 세어 문자열을 자르면 글자 한가운데서 끊길 수 있습니다.
A가가 를 EUC-KR 로 적으면 다섯 바이트입니다. 앞에서 네 바이트만 잘라 내면 마지막 글자가 반토막이 됩니다.
block-beta columns 5 b1["0x41"] b2["0xB0"] b3["0xA1"] b4["0xB0"] b5["0xA1"] l1["A"]:1 l2["가"]:2 l3["가"]:2 c1["네 바이트만 자르면 여기까지"]:4 c2["잘려 나간다"]:1
마지막 칸 하나가 빠지면 남은 0xB0 은 혼자서는 아무 글자도 못 됩니다. 컬럼 길이나 메시지 크기 제한이 바이트 단위인지 글자 단위인지 따져야 하는 이유입니다.
적지 못하는 한글
현대 한글로 조합할 수 있는 음절은 모두 11,172 자입니다. 첫소리 열아홉 개, 가운뎃소리 스물한 개, 끝소리 스물여덟 개(받침이 없는 경우까지 한 칸으로 셉니다)를 곱한 수입니다. 그런데 KS X 1001 에 들어 있는 한글 음절은 그 가운데 2,350 자뿐입니다.
곱해서 불어난 수가 어디서 뭉텅 잘리는지를 그리면 이렇습니다.
flowchart TD
A["첫소리 19"] --> M["곱하면 11,172자"]
B["가운뎃소리 21"] --> M
C["끝소리 28"] --> M
M --> D["KS X 1001 에 담긴 2,350자<br/>자주 쓰는 음절"]
M --> E["번호가 없는 8,822자<br/>뷁 · 똠 · 옛한글"]
자주 쓰는 음절은 다 들어 있지만 드문 음절은 번호가 없습니다. 「뷁」이나 「똠」처럼 흔히 예로 드는 글자들이 그렇습니다. 옛한글(지금은 안 쓰는 자모가 들어간 중세 표기)은 아예 다루지 못합니다.
번호가 없는 글자를 적으려 하면 변환 자체가 실패합니다. 파이썬에서는 이렇게 드러납니다.
"가".encode("euc-kr") # b'\xb0\xa1'
"가".encode("utf-8") # b'\xea\xb0\x80'
"뷁".encode("euc-kr") # UnicodeEncodeError
첫 줄이 돌려준 \xb0 과 \xa1 이 앞에서 본 그 두 바이트입니다. 둘째 줄은 같은 글자를 UTF-8(Unicode Transformation Format 8-bit) 규칙으로 적은 것입니다. 같은 한 글자가 EUC-KR 로는 두 바이트, UTF-8 로는 세 바이트입니다. 셋째 줄은 그 글자의 번호가 목록에 없어서 적지 못하고 예외를 낸 것입니다.
한국어 글만 담는다면 한글이 두 바이트라 파일이 작아집니다. 대신 담기는 글자가 한국어와 영어로 한정됩니다. 같은 문서에 일본어나 악센트가 붙은 유럽 글자를 섞을 수 없습니다.
빈칸을 메운 확장
2,350 자로는 모자란다는 것이 곧 드러났습니다. 그래서 EUC-KR 가 비워 둔 0x80 ~ 0xA0 구간을 첫 바이트로 끌어다 쓰는 확장이 나왔습니다. 남은 음절 8,822 자를 그 구간에 밀어 넣은 것이 CP949(Code Page 949)입니다.
CP949 는 EUC-KR 를 통째로 안에 품습니다. EUC-KR 로 적은 바이트는 CP949 로 읽어도 같은 글자가 됩니다. 한국어 윈도우 환경이 이 확장을 기본으로 삼았습니다. 그래서 널리 퍼졌습니다.
넓힌 대신 내준 것이 있습니다. 확장 영역에서는 두 바이트짜리 글자의 뒤 바이트가 영어 대문자·소문자와 값이 겹칩니다. 바이트만 훑어 영어 글자를 찾는 프로그램이 한글의 뒤 바이트를 글자로 잘못 집을 수 있다는 뜻입니다. 앞 절에서 본 안전함이 확장 영역에서는 깨집니다.
뒤 바이트가 어느 값을 쓰는지 한 줄로 늘어놓으면 겹치는 대목이 보입니다.
block-beta columns 6 a1["0x00~0x40"] a2["0x41~0x5A"] a3["0x5B~0x60"] a4["0x61~0x7A"] a5["0x7B~0xA0"] a6["0xA1~0xFE"] b1["제어·기호"] b2["영어 대문자<br/>CP949 가 끌어다 쓴다"] b3["기호"] b4["영어 소문자<br/>CP949 가 끌어다 쓴다"] b5["빈 구간"] b6["EUC-KR 가 쓴다<br/>영어와 안 겹친다"]
오른쪽 끝 칸만 쓰는 동안은 영어와 부딪힐 일이 없습니다. 확장이 가운데 두 칸까지 내려오면서 겹침이 생겼습니다.
실무에서는 EUC-KR 라고 적어 두고 실은 CP949 로 저장한 파일이 자주 나옵니다. 읽을 때 CP949 로 열면 EUC-KR 파일도 함께 읽히므로, 한국어 옛 파일은 CP949 쪽으로 여는 편이 덜 깨집니다.
이 바이트가 무엇인지 알리는 방법
바이트만 봐서는 이 바이트열이 EUC-KR 인지 알 수 없습니다. 0x7F 을 넘는 바이트는 어느 인코딩에서나 나옵니다. 그 값이 무슨 글자인지는 규칙마다 다릅니다. 인코딩 이름을 바이트 바깥에서 따로 알려 줘야 하는 이유입니다.
알리는 통로는 쓰는 곳마다 다릅니다. 웹 문서는 Content-Type charset 으로 알립니다. 데이터베이스는 열이나 연결의 문자 집합 설정으로, 프로그램은 파일을 열 때 넘기는 인코딩 이름으로 알립니다.
이름이 여기저기서 같은 뜻으로 통하려면 표기가 한곳에 모여 있어야 합니다. IANA(Internet Assigned Numbers Authority) 는 인터넷에서 쓰는 이름과 번호를 관리하는 기관입니다. 이 기관이 문자 집합 이름을 모아 둔 공식 목록에 EUC-KR 라는 이름이 올라 있습니다.
알린 이름과 실제 바이트가 어긋나면 글자가 깨집니다. 한글 두 바이트를 한 바이트짜리 글자 둘로 읽어 뜻 없는 기호가 줄줄이 나오는 현상을 모지바케라고 부릅니다.
오늘 이 바이트를 만나는 곳
새로 만드는 시스템은 대개 UTF-8 을 씁니다. EUC-KR 는 주로 옛것을 넘겨받을 때 나옵니다. 관공서와 금융권이 내려 주는 파일, 오래된 게시판과 홈페이지, 오래 굴러온 데이터베이스의 옛 열, 스프레드시트가 열어 주는 쉼표 구분 파일이 그런 것들입니다.
흔한 처리 방식은 하나입니다. 넘겨받은 바이트는 읽는 즉시 유니코드 문자열로 바꿉니다. 시스템 안에서는 한 가지 인코딩만 씁니다. 명령줄에서는 iconv 같은 변환 도구가 파일 하나를 통째로 옮겨 줍니다.
바꿀 때 걸리는 대목이 하나 있습니다. 유니코드에서 EUC-KR 로 되돌릴 때는 EUC-KR 에 번호가 없는 글자가 그대로 막힙니다. 한쪽으로만 온전히 흐르는 변환입니다. 되돌릴 일이 있으면 그런 글자를 버릴지 다른 글자로 바꿀지 먼저 정해 두어야 합니다.
관련 항목
EUC-KR 가 속하는 상위 분류
문자 인코딩 · 문자 집합 · 포맷 · 멀티바이트 인코딩 · 코드 페이지
EUC-KR 가 담을 글자를 정하는 표준
KS X 1001 · KSC-5601 · ASCII · 한글 음절 · 완성형 · 조합형
EUC-KR 를 넓히거나 대신하는 인코딩
CP949 · UTF-8 · UTF-16 · 유니코드 · ISO-2022-KR · Shift_JIS · ISO-8859-1 · windows-1252
EUC-KR 임을 알리고 바꾸는 데 쓰는 수단
Content-Type charset · meta charset · IANA 문자 집합 레지스트리 · iconv · 로케일 · 바이트 순서 표시
EUC-KR 바이트를 잘못 읽었을 때 겪는 문제
다른 이름: euc-kr · euckr · EUC_KR · Extended Unix Code for Korean · 한국어 EUC