합동회사 코무라소프트
1장

도입 — 문자 깨짐은 왜 일어나는가

파일의 실체는 바이트 열뿐. 「쓴 인코딩」과 「읽은 인코딩」이 어긋나면 같은 바이트 열이 다른 문자로 보인다 — 문자 깨짐의 정체를 여기서 다진다.

「縺薙s縺ォ縺。縺ッ」— 이 화면, 무슨 일이 일어나고 있는가

거래처에서 온 CSV 를 Excel 로 열었더니 일본어가 전부 「縺薙s縺ォ縺。縺ッ」 같은 한자 나열이 되어 있었다. 웹 페이지의 일부만 「ã“ã‚“」 같은 기호가 늘어선다. DB 에 등록했을 이름이 「????」가 되어 있다. — 대처로 「인코딩을 바꿔서 다시 열었더니 고쳐졌다」는 경험은 있어도, 왜 그것으로 고쳐지는가를 설명할 수 있는 사람은 의외로 적습니다.

출발점은 단 1 가지 사실입니다. 컴퓨터가 저장하거나 보낼 수 있는 것은 0x00〜0xFF 의 바이트의 나열뿐. 일본어 문자 「あ」나 「A」라는 문자 그 자체가 저장되는 것이 아닙니다. 문자를 바이트 열로 변환하는 규칙을 인코딩(부호화)이라 부르며, UTF-8 도 Shift_JIS 도 이 규칙의 일종입니다.

그리고 중요한 것이 다음 지점입니다. 파일에는 「이 바이트 열은 UTF-8 입니다」라는 표찰이 붙어 있지 않습니다. 읽는 쪽은 설정이나 선언이나 추측에 기대어 「아마 이 인코딩이겠지」라고 정하고 대응표를 찾습니다. 쓴 쪽의 규칙과 읽는 쪽의 규칙이 일치하면 원래 문자로 돌아오고, 어긋나면 — 다른 문자로 보입니다. 이것이 문자 깨짐입니다.

바이트 열 E3 81 AB 가 UTF-8 에서는 일본어 「に」, Shift_JIS 에서는 「縺ォ」, Latin-1 에서는 「ã«」로 읽히는 것을 보여 주는 그림

같은 3 바이트가, 찾아보는 대응표에 따라 「に」 「縺ォ」 「ã«」로 깨집니다. 바이트 열은 1 비트도 변하지 않았다는 점이 최대의 포인트입니다.

깨져도, 데이터는 깨지지 않았다

위의 그림을 다시 한번 보세요. E3 81 AB 라는 3 바이트는, 어느 방식으로 읽어도 완전히 같은 3 바이트 그대로입니다. 깨진 것은 데이터가 아니라 「읽는 방식의 선택」뿐. 그러므로 올바른 인코딩을 지정해서 다시 읽으면, 원래의 「に」가 그대로 돌아옵니다.

다만 1 가지만 주의가 있습니다. 깨진 모습 그대로 덮어써 저장해 버리면, 「縺ォ」라는 깨진 문자열이 새로운 바이트 열로 디스크에 기록되고, 원래 바이트 열은 사라집니다. 문자 깨짐을 만나면 「쓰지 말고, 먼저 읽는 방식을 의심한다」 — 이것이 실무에서의 첫 동작입니다.

이 강좌의 구호: 문자 깨짐을 보면 물어보세요 — 어느 인코딩으로 쓰인 바이트 열을, 어느 인코딩으로 읽어 버렸는가?

소문제 1-1 — 파일의 실체는 바이트 열뿐

문자 깨짐의 정체를, 바이트 열과 읽는 방식의 관계로 말할 수 있는지 확인합니다.

Q1. 텍스트 파일로 디스크에 저장되어 있는 「실체」는 무엇입니까.

Q2. 같은 바이트 열 E3 81 AB 를 UTF-8 로 읽으면 일본어 문자 「に」, Shift_JIS 로 읽으면 「縺ォ」로 보입니다. 이 현상의 설명으로 올바른 것은 어느 것입니까.

Q3. 문자가 깨진 파일에 대해, 대부분의 경우에 올바른 설명은 어느 것입니까.

「번호를 매긴다」와 「바이트로 만든다」— 2 단계로 나누어 생각한다

여기서 이 강좌 전체를 관통하는 관점을 도입합니다. 문자가 바이트 열이 되기까지에는, 실은 2 개의 독립된 단계가 있습니다.

제 1 단계 — 문자 집합(어느 문자에 번호를 매기는가)
세상의 문자를 모아, 하나씩 번호를 할당한 표. Unicode 에서는 일본어 문자 「あ」에 U+3042 라는 번호가 매겨져 있습니다. 이 번호를 코드 포인트라고 부릅니다
제 2 단계 — 인코딩(번호를 어떻게 바이트로 만드는가)
코드 포인트를 바이트 열로 변환하는 규칙. 같은 U+3042 라도, UTF-8 이라면 E3 81 82, UTF-16 이라면 30 42 로 결과가 달라집니다

「Unicode 와 UTF-8 은 뭐가 달라?」라는 단골 의문은, 이 2 단계로 즉답할 수 있습니다. Unicode 는 제 1 단계(번호를 매기는 방식), UTF-8 은 제 2 단계(번호를 바이트로 바꾸는 방식). 토지의 번지를 정하는 방식과, 번지를 봉투에 어떻게 쓰는가의 차이라고 해도 좋겠습니다. 제 2 장에서 제 1 단계를, 제 3 장 이후에서 제 2 단계를 각각 차분히 다룹니다.

소문제 1-2 — 문자 집합과 인코딩을 구별한다

이 강좌를 관통하는 2 단계 — 번호를 매긴다(문자 집합)와 바이트로 만든다(인코딩) — 의 구별을 확인합니다.

Q4. 「문자 집합」과 「인코딩」의 역할 분담으로 올바른 것은 어느 것입니까.

Q5. 「이 파일은 Unicode 로 저장되어 있습니다」라는 표현이 부정확한 이유는 어느 것입니까.

이 장에서 가져갈 것

  • 파일의 실체는 바이트 열뿐. 「무슨 인코딩인가」의 표찰은 붙어 있지 않다
  • 문자 깨짐의 정체는 「쓴 인코딩」과 「읽은 인코딩」의 어긋남. 바이트 열 자체는 깨지지 않은 경우가 많고, 읽는 방식을 고치면 돌아온다(단, 깨진 채로 저장하지 않는다)
  • 문자는 번호(코드 포인트) → 바이트 열(인코딩)의 2 단계로 다루어진다. Unicode 는 제 1 단계, UTF-8 은 제 2 단계

다음 장에서는 제 1 단계 「번호를 매긴다」의 역사를, ASCII 의 128 문자에서 세계의 모든 문자를 담는 Unicode 까지 단숨에 따라갑니다.