다음 이전 차례

7. UTF-8은 무엇인가?

무엇보다 먼저 UCS와 유니코드는 단지 정수를 문자에 할당하는 코드 테이블일 뿐이 라는 것이다. 그러한 문자 혹은 문자 각각의 정수 값의 시퀀스가 어떻게 바이트 시퀀스로 나타날 수 있는 지에 대한 몇 가지 대안들이 존재한다. 대단히 이해하기 쉬운 두 개의 인코딩은 유니코드 텍스트를 2 혹은 4바이트 시퀀스의 시퀀스(sequences of eit her 2 or 4 bytes sequences)로써 저장한다. 이러한 용어에 관한 공식적인 명칭은 각 각 UCS-2와 UCS-4이다. 다른 방법으로 명시되지 않는다면, 가장 중요한 바이트가 이들의 첫번째로 온다(Bigendian convention). ASCII 또는 Latin-1 파일은 모든 ASCII 바이트의 앞에 0x00 바이트를 삽입하므로써, UCS-2 파일로 변환시킬 수 있다. UCS-4 파일을 원한다면, 모든 ASCII 바이트 앞에 그 대신에 세개의 0x00 바이트를 삽입해야만 한다.

유닉스 환경에서 UCS-2(또는 UCS-4)를 사용하는 것은 매우 심각한 문제점을 불러온 다. 이러한 인코딩을 가진 문자열들은 파일명과 C 라이브러리 함수 파라미터에서 특별 한 의미를 갖는 '\0' 혹은 '/'와 같이 매우 광범위한 문자 바이트를 부분적으로 포함할 수 있다. 이에 더해, 대다수의 유닉스 툴들은 ASCII 파일을 예상하며, 큰 수정이 없이는 16비트 단어들을 문자로 읽을 수 없다. 이러한 이유 때문에 UCS-2는 파일명과 텍스트 파일 및 환경 변수 등에 적합한 유니코드의 외부 인코딩(suitable external encoding of Unicode)이 아니다.

ISO 10646-1 의 Annex RRFC 2279상에 정의된 UTF-8 인코딩은 이러한 문제점들이 없다. 이것은 유닉스 스타일의 운영 체제하에서 유니코드를 사용하기 위한 의심할 여지없이 좋은 방법이다.

UTF-8은 다음의 성질을 갖고 있다:

다음의 바이트 시퀀스는 한 문자를 나타내기 위해 사용한다. 사용되는 시퀀스는 그 문자의 유니코드 번호에 따라 달라진다.


U-00000000 - U-0000007F:
0xxxxxxx
U-00000080 - U-000007FF: 110xxxxx 10xxxxxx
U-00000800 - U-0000FFFF: 1110xxxx 10xxxxxx 10xxxxxx
U-00010000 - U-001FFFFF: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
U-00200000 - U-03FFFFFF: 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
U-04000000 - U-7FFFFFFF: 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx

xxx비트의 위치는 이진 표기법에 의해 문자 코드 번호의 비트들로 채워진다. 오른쪽의 x비트는 별로 중요하지 않다. 그 문자의 코드 번호를 나타내는 오직 가장 짧은 멀티바이트 시퀀스만 사용할 수 있다. 멀티바이트 시퀀스에서 첫 번째 바이트의 왼쪽 1비트의 수는 전체 시퀀스에서의 바이트 수와 같다는 점에 주의하라.

예: "유니코드 문자 U+00A9 = 1010 1001"(저작권 부호)는 다음과 같은 UTF-8에 따라 인코딩된다.

11000010 10101001 = 0xC2 0xA9

그리고 문자 U+2260 = 0010 0010 0110 0000(저작권 부호)는 다음과 같은 UTF-8에 따라 인코딩된다.

11100010 10001001 10100000 = 0xE2 0x89 0xA0

이러한 인코딩의 공식 명칭과 정확한 표기는 UTF-8이며, UTF는 UCS Transformation Format을 의미한다. utf8혹은 UTF_8과 같은 다른 방법으로 UTF-8을 문서에 쓰지마라. 물론 인코딩 자체를 참조하지 않고 변수명에 참조할 경우에는괜찮다.

UTF-8의 디코딩 처리 순서에 있어서 중요한 점은 다음과 같다: 보안상의 이유 때문에, UTF-8 디코더는 한 문자를 인코딩하기 위해서 필요 이상으로 긴 UTF-8 시퀀스를 받아들여서는 안 된다. 예를 들어 U+000A(라인 피드) 문자는 오직 0x0A 형식으로 UTF-8 스트림으로부터 받아들여야만 하며, 다음의 다섯가지와 같이 과도하게 긴(overlong) 형식으로 받아들여서는 안된다.

  0xc0 0x8A
  0xe0 0x80 0x8A
  0xf0 0x80 0x80 0x8A
  0xf8 0x80 0x80 0x80 0x8A
  0xfc 0x80 0x80 0x80 0x80 0x8A

가장 짧은 인코딩을 찾기 위한 UTF-8 서브스트링 테스트를 무시하기 어떤 과도하게 긴 UTF-8 시퀀스를 남용할 수 있다. 모든 과도하게 긴 형식의 UTF-8 시퀀스는 다음의 바이트 패턴 중 한 가지로 시작한다.


1100000x (10xxxxxx)
11100000 100xxxxx (10xxxxxx)
11110000 1000xxxx (10xxxxxx 10xxxxxx)
11111000 10000xxx (10xxxxxx 10xxxxxx 10xxxxxx)
11111100 100000xx (10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx)

정상적인 UTF-8 혹은 UCS-4 데이터상에서 코드 위치 U+FFFE와 U+FFFF 뿐만 아니라 코드 위치 U+D800 부터 U+DFFF(UTF-16 대용)까지는 사용해서는 안 된다. UTF-8 디코더는 이러한 것들을 안전성을 이유로, 잘못된 형식으로 혹은 너무 긴 시퀀스로 취급해야 만 한다.

Markus Kuhn의 UTF-8 decoder stress test file은 잘못된 형식을 갖는 과도하게 긴 UTF-8 시퀀스의 체계적인 모음을 포함하고 있으며 디코더의 강력함을 증명해준다.


다음 이전 차례