Shift_JIS 와 일본어의 사정 — 다메 문자와 CP932
Shift_JIS 는 2 번째 바이트가 ASCII 영역에 파고드는 설계. 거기서 태어나는 「다메 문자」 문제와, 반각 가나·CP932·지금도 현역인 이유를 구조로부터 이해한다.
「ソフト」라고 입력하면 깨진다 — 거짓말 같은 진짜 버그
오래된 업무 시스템에서 「ソフト(소프트)」라는 단어를 저장하면, 왠지 그 행만 데이터가 무너진다. 파일 경로에 일본어 한자 「表」를 포함하는 폴더를 만들면 특정 도구가 실패한다. — Shift_JIS 의 현장에는, 이런 언뜻 오컬트 같은 버그의 전설이 있습니다. 이 장의 목표는, 이것을 구조로부터 설명할 수 있게 되는 것입니다.
Shift_JIS 는, Unicode 이전 시대에 「ASCII 와 공존하면서 일본어를 밀어 넣기」 위해 만들어진 일본어권의 레거시 인코딩입니다 — 한국어권의 EUC-KR/CP949 와 비슷한 위치라고 생각하면 이해하기 쉽습니다. ASCII 는 1 바이트 그대로, 전각 문자는 2 바이트로 나타냅니다.
문제는 2 번째 바이트의 범위입니다. 0x40〜0x7E 는, ASCII 의 영문자나 기호와 통째로 같은 값. 즉 전각 문자의 후반 1 바이트만 꺼내면, ASCII 의 기호와 구별이 되지 않습니다. 앞 장에서 본 UTF-8 의 「다바이트 문자의 구성 바이트는 모두 0x80 이상」이라는 보증이, 여기에는 없는 것입니다.
「表」의 2 번째 바이트 0x5C 는, ASCII 에서는 백슬래시. 바이트 단위로 주사하는 프로그램에는 「表」의 후반이 기호로 보여 버립니다.
다메 문자 — 2 번째 바이트 0x5C 의 충돌
ASCII 의 0x5C 는 백슬래시 \(일본어 환경에서는 엔화 기호로 표시되는 일도 많은 문자)입니다. 많은 프로그래밍 언어나 설정 파일에서 「다음 1 문자를 특별 취급한다」는 이스케이프 기호로 사용됩니다.
여기서 Shift_JIS 의 「表」를 봅시다. 바이트 열은 95 5C — 2 번째 바이트가 딱 0x5C 입니다. Shift_JIS 를 의식하지 않고 바이트 단위로 문자열을 주사하는 처리계는, 95 다음의 5C 를 독립된 백슬래시로 오해하고, 다시 다음 바이트를 이스케이프로 소비합니다. 결과적으로 「表」의 후반이 먹혀 문자가 이지러지고, 이후의 해석이 연쇄적으로 어긋난다 — 서두의 「오컬트 버그」의 정체입니다.
2 번째 바이트가 0x5C 가 되는 문자는 「ソ(83 5C)」 「能(94 5C)」 「表(95 5C)」 「十」 「予」 「構」 등 다수 있으며, 일본에서는 속칭 다메 문자(ダメ文字, 안 되는 문자)라고 불립니다. 어느 것이나 일상어에 평범하게 나타나는 문자라서, 「특정 단어일 때만 깨진다」는 재현 조건을 잡기 어려운 장애가 됩니다. 0x5C 이외에도, 2 번째 바이트가 "(0x22)나 |(0x7C) 등에 해당하는 조합으로 같은 종류의 문제가 일어날 수 있습니다.
소문제 4-1 — 2 바이트 구조와 다메 문자
Shift_JIS 의 구조로부터, 왜 특정 문자만이 트러블을 일으키는지를 끌어냅니다.
Q1. Shift_JIS 의 구조 설명으로 올바른 것은 어느 것입니까.
Shift_JIS 는 ASCII 호환을 유지하면서 2 바이트로 한자를 밀어 넣은 설계이지만, 2 번째 바이트에 0x40〜0x7E 라는 ASCII 의 영문자·기호와 같은 값의 범위를 사용했습니다. 즉 「전각 문자의 후반 바이트」만 보면 ASCII 의 기호와 구별이 되지 않습니다. UTF-8 같은 「다바이트 문자의 구성 바이트는 모두 0x80 이상」이라는 보증이 없다는 것이, 다음 문제의 복선이 됩니다.
Q2. Shift_JIS 에서 일본어 한자 「表」는 95 5C 의 2 바이트입니다. 이 문자를 포함하는 문자열을, 0x5C 를 이스케이프 기호(백슬래시)로 특별 취급하는 처리계에 통과시키면 깨지는 일이 있습니다. 이유는 어느 것입니까.
Shift_JIS 를 모르는(또는 바이트 단위로 처리하는) 프로그램에는, 95 5C 가 「95 라는 무언가」와 「백슬래시」로 보입니다. 백슬래시를 발견하면 다음 문자를 이스케이프로 소비하기 때문에, 「表」의 후반이 먹히고, 이후의 해석이 연쇄적으로 어긋납니다. 문자 깨짐이라기보다 「데이터 파괴」에 가까운 증상이 되는 것이, 이 다메 문자 문제의 무서움입니다.
Q3. 이른바 「다메 문자」에 해당하는 예의 조합으로 올바른 것은 어느 것입니까.
2 번째 바이트가 0x5C(백슬래시)가 되는 문자가 대표적인 다메 문자로, 「ソ」 「能」 「表」 「十」 「予」 등이 해당합니다. 회사명이나 메시지에 평범하게 나타나는 문자들뿐이라서, 「ソフト(소프트)」라는 단어에서 장애가 일어난다는, 언뜻 불가해한 버그 신고가 됩니다. 히라가나나 영문자가 일률적으로 안 되는 것이 아니라, 우연히 2 번째 바이트가 기호의 값에 해당한 문자만이 문제가 된다 — 구조를 모르면 절대로 추리할 수 없는 현상입니다.
CP932 — 「Shift_JIS」를 자칭하는 방언
또 1 가지 현장 지식이 기종 의존 문자입니다. 원 숫자 ①, ㈱, 로마 숫자 Ⅱ, 「髙」(사다리 다카) — 이것들은 원래 JIS 규격의 문자 집합에는 없고, 제조사가 독자적으로 추가한 문자였습니다. Windows 는 이것들을 받아들인 확장판 CP932 를 「Shift_JIS」로 사용하고 있습니다.
즉, 세간에서 「Shift_JIS 파일」이라 불리는 것의 다수는, 정확하게는 CP932 입니다. 같은 이름을 자칭하는, 미묘하게 다른 표가 여럿 있다 — ① 이 든 데이터를 엄밀한 Shift_JIS 로 변환하려 하면 실패하고, 환경에 따라 깨지는 문자가 달라진다는 성가신 사정의 뿌리입니다. 「Shift_JIS 관련 트러블에서는, 진짜 표는 CP932 가 아닐까」라고 한 단계 의심하는 것이 실무의 요령입니다.
그런데도 Shift_JIS 가 현역인 이유
웹의 세계는 UTF-8 로 거의 통일되었습니다. 그런데도 Shift_JIS(CP932)가 사라지지 않는 것은, 인코딩의 이행이 「나만 바꾸면 되는」 문제가 아니기 때문입니다. 파일을 주고받는 상대 — Excel 의 종래 형식 CSV, 오랜 세월 가동하는 기간 시스템, 금융·행정계의 고정 길이 파일 연계 — 의 보조가 갖추어지지 않는 한, 주고받는 부분에는 오래된 인코딩이 계속 남습니다.
그래서 이 강좌에서는 Shift_JIS 를 「과거의 유물」이 아니라 「지금도 추리의 대상이 되는 현역 용의자」로 다룹니다. UTF-8 파일을 Shift_JIS 로 읽는다, Shift_JIS 파일을 UTF-8 로 읽는다 — 이 양방향 오독 패턴의 구별법은, 제 7 장 종합 연습의 주역입니다.
소문제 4-2 — 반각 가나·CP932·현역인 이유
Shift_JIS 주변의 실무 지식을 마무리합니다.
Q4. Shift_JIS 에서의 반각 가나(アイウエオ…)의 설명으로 올바른 것은 어느 것입니까.
반각 가나는 전신·초기 단말 시대부터 사용되어 온 1 바이트의 가나(JIS X 0201 유래)로, Shift_JIS 에서는 0xA1〜0xDF 에 1 바이트로 담겨 있습니다. 2 바이트 문자의 1 번째 바이트(0x81〜0x9F, 0xE0〜0xFC)는 이 영역을 피해서 배치되어 있으며, 「Shift(비켜 놓기)」라는 이름은 이 변통에서 유래합니다. 제 7 장에서는, UTF-8 을 Shift_JIS 로 오독했을 때 반각 가나가 섞여 보이는 이유로도 재등장합니다.
Q5. CP932 와 Shift_JIS 의 관계로 올바른 것은 어느 것입니까.
Windows 의 「Shift_JIS」의 실체는 CP932 라는 확장판으로, NEC·IBM 유래의 기종 의존 문자(①, ㈱, 髙 등)가 추가되어 있습니다. 같은 「Shift_JIS」를 자칭해도 환경에 따라 미묘하게 표가 다르기 때문에, ①을 포함하는 데이터가 다른 환경에서 깨진다·변환에 실패한다는 사고가 일어납니다. 「Shift_JIS 라고 하면, 실제로는 CP932 인 경우가 많다」는 실무에서 도움이 되는 경험칙입니다.
Q6. UTF-8 이 표준이 된 현재도, Shift_JIS(CP932)를 다루는 장면이 남아 있는 이유로 가장 적절한 것은 어느 것입니까.
문자 코드의 이행은 「나만 바꾸면 되는」 것이 아니라, 파일을 주고받는 상대 시스템 전체의 보조의 문제입니다. Excel 에서 더블 클릭으로 열리는 CSV, 금융·행정계의 고정 길이 파일, 오래된 POS 나 기간 시스템 등, Shift_JIS 전제의 연계는 지금도 대량으로 가동 중입니다. 그렇기에 「받은 파일이 어느 쪽 인코딩인가」를 추리하는 기술(제 7 장)에 실무 가치가 있는 것입니다.
이 장에서 가져갈 것
- Shift_JIS 는 ASCII 1 바이트 + 전각 2 바이트이지만, 2 번째 바이트가 ASCII 의 값 범위(0x40〜0x7E)에 파고든다
- 다메 문자 = 2 번째 바이트가 0x5C 등의 기호에 해당하는 문자(ソ 83 5C·能 94 5C·表 95 5C 등). 이스케이프 처리와 충돌하여 데이터가 깨진다
- 반각 가나는 0xA1〜0xDF 의 1 바이트. Windows 의 「Shift_JIS」의 실체는 기종 의존 문자가 든 CP932
- Excel 의 CSV 나 레거시 연계 때문에 지금도 현역. 오독 패턴의 추리 대상으로서 인연은 계속된다
다음 장은 Unicode 쪽의 또 하나의 인코딩, UTF-16 으로. 이번에는 「바이트 수」가 아니라 「문자 수를 세는 방법」이 함정이 됩니다.