'UTF-8'에 해당되는 글 1건

  1. 2008.04.20 [스크랩] 문자셋과 인코딩, 유니코드에 관하여 (5)

(출처: kbg 6th님의 블로그 - http://which.tistory.com/1)

UTF-8이 무엇일까? 또한 ASCII, UNICODE 등의 단어가 뜻하는 것이 무엇일까?

인터넷을 하다보면 다음과 같은 화면을 접할 때가 있다.

사용자 삽입 이미지

인 터넷 익스플로러로 구글에 접속한 후 메뉴에서 '보기'>'인코딩'>'한국어'를 선택하면 위와 같이 한글이 알아보기 어려운 문자로 깨어져 출력이 된다. 인코딩을 유니코드(UTF-8)로 하면 아래와 같이 정상적인 한글이 출력된다.

사용자 삽입 이미지


인 코딩(encoding)이란 컴퓨터에 '1000001'과 같이 숫자로 저장되어 있는 텍스트를 우리가 알아볼 수 있는 'A'와 같은 글자로 바꾸어주는 기능을 말한다. 그런데 '1000001'을 글자로 바꿀 때 어떤 글자로 바꿀지에 대한 규약이 여러 개가 있기 때문에 동일한 숫자(01000001)로 저장되어 있는 텍스트라도 인코딩을 '한국어'로 할 때와 '유니코드(UTF-8)'로 할 때 각각 다른 글자로 바뀌게 된다. (위 화면에서 인코딩을 '한국어'로 할 때는 중세 훈민정음 같이 나오던 글자들이 '유니코드(UTF-8)'로 인코딩을 하니 현대 표준어로 나오는 것이 신기하지 않은가?)

인코딩을 한국어나 유니코드(UTF-8)로 한다고 할 때 한국어, 유니코드(UTF-8)를 문자셋(character set)이라고 부른다. 'A', 'B', '가', '1' 등의 문자들을 모아놓은 집단이라는 의미이다. 컴퓨터 시대가 시작되면서 미국에서는 알파벳과 숫자를 포함한 수 십개의 글자에 고유번호를 부여하여 사용하였다. 그런데 각 컴퓨터 제조 회사들이 독자적으로 번호를 할당하여 사용하였기 때문에 IBM 컴퓨터에서 만든 텍스트를 다른 회사의 컴퓨터에서는 제대로 읽을 수 없는 문제가 생겼다. 이를 해결하기 위해 ANSI(American National Standards Institute, 미국표준협회)에서는 1960년에 ASCII(American Standard Code for Information Interchange)라는 규약을 만들었다. 미국에서는 알파벳과 숫자 등을 모두 합쳐도 128글자가 되지 않는다. 2^7=128 이므로 7비트로 한 글자를 표현할 수 있다. 이 당시는 컴퓨터의 메모리가 매우 비싼 시절이었기 때문에 ASCII는 1바이트(8비트)가 아닌 7비트로 한 글자를 표현한다. 아래에 ASCII 문자셋이 나와 있다.

사용자 삽입 이미지


위 문자셋에서 출력가능한 문자는 94개이고, 나머지는 제어코드라고 불리는 것들이다. 제어코드는 키보드의 Space키 등과 같은 특수한 효과를 나타내는 코드들을 지칭한다. 컴퓨터에 'Apple'이라는 단어를 저장하고 싶다면 ASCII를 따를 경우

텍스트 16진수 2진수
A 0x41 1000001
p 0x70 1110000
p 0x70 1110000
l 0x6C 1101100
e 0x65 1100101

로 저장하면 된다. 그런데 미국 사람들만 사용하던 컴퓨터를 유럽 사람들도 사용하기 시작했다. 이 사람들은 기본적으로 알파벳을 사용하고 있었으나 나라마다 독특한 글자가 몇 개씩 존재하였다. 예를 들면 독일에서는 'a', 'o' 등의 글자 위에 점을 두 개 붙인 글자도 존재한다. 혹은 그리스의 알파나 감마를 표현해야 할 때도 있다. 그리고 컴퓨터는 기본적으로 2의 거듭제곱으로 메모리 등의 숫자가 커지므로 애초에 7비트로 한 글자를 표현한다는 것은 불편함을 가지고 있었다. 시간이 흘러 수 많은 컴퓨터의 보급과 함께 메모리의 가격도 많이 낮아져 사람들은 8비트(1바이트)로 한 글자를 표현하게 되었다. 1비트가 늘어남에 따라 기존 ASCII의 128글자 이외에 새로이 128글자를 더 사용할 수 있게 되었다. 각 국가에서는 이 새로운 공간에 자신들의 언어를 집어넣기 시작했다. 이러한 각각의 문자셋을 코드페이지라고 부른다. 기본적으로 모든 코드페이지는 총 256글자 중 첫 128글자는 ASCII를 따르고 나머지 128글자만을 자신들의 입맛에 맞게 바꾼다. IBM PC와 MS-DOS에서 가장 널리 사용되는 코드페이지는 437(cp 437)이고, ISO/IEC 8859-1이라고 부른다.

그런데 컴퓨터가 미국에서 시작해 대서양을 지나 유럽으로 보급된 후 시간이 흘러 중동, 아시아에까지 보급이 되었다. 이 지역에서 사용하는 언어는 글자수가 매우 많다는 특징이 있다. 예를 들면 8비트가 표현할 수 있는 256글자로는 한글의 모든 글자를 나타내기에는 턱없이 부족하다. (또한 우리가 중학교 때 배운 한자를 생각해보라) 이 지역의 컴퓨터 전문가들은 2바이트(16비트)를 이용해 한 글자를 표현하는 아이디어를 생각해냈고 각 나라별로 자체 표준을 만들어 사용하였다. 2바이트로는 65,536글자를 사용할 수 있어 대부분의 언어에서는 큰 문제없이 글자를 표현할 수 있었다. (하지만 1바이트 문자셋에 비해 불편한 점이 많았다) 한글의 경우에는 (1)자음과 모음 각각에 5비트를 할당한 후 이를 조합하여 한 글자를 표현하는 조합형 방식과 (2)자음과 모음이 합쳐진 한 글자에 16비트를 할당해 표현하는 완성형 방식이 각자의 장단점을 가진 채 개발되었다. 1987년, 완성형 방식이 KS-5601 국가 표준으로 채택되고 조합형 방식은 한글과컴퓨터사의 아래아한글의 지원을 받았으나 윈도95가 완성형 방식을 사용함으로 인해 사양길에 들었다. (참고로 조합형 방식은 한글의 모든 11,172글자를 표현할 수 있으나 완성형 방식은 2,350글자 밖에 표현할 수 없다)

각 국에서 자신들만의 2바이트 문자셋을 만들어 쓰는 것이 그 나라 안에서만 정보가 이동할 경우에는 큰 문제가 없다. 하지만 세계가 점점 더 연결됨에 따라 국가 간 정보의 교류가 늘어났다. 이렇게 되자 일본어로 작성된 문서를 한국의 컴퓨터에 전송할 경우 문자셋이 맞지 않아 제대로 된 일본어를 읽을 수 없는 경우가 많이 생겼다. 일정한 표준이 없어 한 국가에서 만든 프로그램을 다른 국가로 수출할 때 그 국가에 맞는 문자셋을 추가시켜야 하는 문제도 생겼고, 러시아 같은 경우는 한 나라 안에서도 몇 개의 문자셋이 존재하였다. 이 문제들을 해결하기 위해 전문가들은 유니코드(unicode)라는 개념을 만들었다. 자세한 내용은 어렵지만 간단히 얘기하면 전 세계의 모든 언어에서 사용되는 글자들을 모아 하나의 문자셋을 만드는 것이다. 유니코드에는 각 언어의 글자마다 코드포인트(code point)가 할당되어 있다. 예를 들면 'ㄱ'의 코드포인트는 U+1100이고 '가'는 U+AD00이다.

유니코드는 어떻게 해서 전 세계의 모든 언어에서 사용되는 글자들을 다 표현할 수 있을까? 4바이트로 한 글자를 표현한다면 충분히 가능한 이야기이다. (현재까지는 3바이트로 세계의 거의 모든 글자를 표현한다) 하지만 컴퓨터 세계에서 가장 많이 쓰이는 영어의 경우에는 1바이트보다 작은 단지 7비트만 있으면 되는데 한 글자를 표현하기 위해서 4바이트나 쓰라는 것은 낭비일 수 있다. 따라서 현재 유니코드의 인코딩 방식 중 4바이트로 한 글자를 표현하는 방식은 잘 쓰이지 않고 있고 2바이트로 한 글자를 표현하는 방식이 널리 쓰인다. 또한 유니코드를 표준 문자셋으로 사용한다면 기존의 8비트 ASCII 방식으로 저장된 수 많은 문서들과 ASCII 방식을 사용하는 컴퓨터와의 호환문제는 어떻게 할 것인가? 이를 해결하기 위한 아이디어가 바로 UTF-8이다. UTF란 Unicode Transformation Format의 줄임말로 유니코드의 코드포인트를 우리가 쓰는 글자로 인코딩하는 방식을 말한다. UTF-8은 코드포인트를 8비트 단위로 1바이트(8비트), 2바이트(16비트) 등 가변적으로 읽어들여 글자를 표현한다. 이 인코딩 방식의 장점은 ASCII 방식과 호환이 가능하다는 점이다. 코드포인트 U+0000부터 U+007F까지의 128글자는 1바이트로 처리하기 때문이다. 예를 들어 'A'는 코드포인트가 U+0041(00000000 01000001, 2바이트)이다. (이는 ASCII의 0x41(01000001, 1바이트)과 비슷하게 맞추어 놓은 것이다) U+0041은 앞의 범위 안에 들기 때문에 00000000 01000001(2바이트)을 UTF-8 인코딩에서는 01000001(1바이트)로 처리한다. 따라서 UTF-8인코딩을 이용해 저장한 텍스트는 ASCII를 사용하는 컴퓨터에서 제대로 읽을 수 있다. 또한 ASCII에서의 'A', 즉 0x41은 2진수로 01000001이다. 자세히 살펴보면 최상위비트가 0임을 알 수 있다. UTF-8의 규약에 의해 최상위비트가 0인 코드는 1바이트로 처리한다. 따라서 ASCII로 저장된 'A'라는 글자는 UTF-8을 사용하는 컴퓨터에서도 1바이트로 'A'라고 인식될 수 있다. 이러한 호환성 때문에 UTF-8은 현재 널리 쓰이는 유니코드 인코딩 방식이 되었다.

이 제 첫 부분에 나왔던 구글의 깨진 글자를 분석해보자. 지금까지의 논의를 생각해 본다면 전혀 이해할 수 없게 보이는 글자들이 어떤 규칙을 가지고 있을 것임을 예상할 수 있다. 첫 줄의 'Google 怨꾩젙'을 살펴보자. 유니코드(UTF-8)로 작성된 'Google 계정'이라는 글자가 한국어라는 문자셋에서는 'Google 怨꾩젙'이라고 출력된 것이다. (UTF-8은 ASCII와 호환이 되고, ASCII의 나머지 128글자를 쓰는 한국어 문자셋에서도 처음 128글자는 ASCII를 따르므로 'Google'은 문자셋에 상관없이 제대로 표현이 되었다) 먼저 '계'의 코드포인트는 U+ACC4이다. 이는 2진수로 10101100 11000100(2바이트)라고 생각할 수 있지만 UTF-8규약에 의하면 최상위 몇 비트는 한 글자가 몇 바이트를 차지하는지 알리는 데 써야 하므로 11101010 10110011 10000100(3 바이트)가 된다. 제일 처음 나오는 1110은 이 글자가 3바이트를 차지함을 알려준다. 그 다음 각 바이트의 10은 현재 바이트가 앞 바이트의 종속 바이트임을 알려준다. 그리고 나머지 비트를 실제 코드포인트가 차지하는 것이다. (자세한 내용은 위키피디아에서 'utf-8'을 검색하면 알 수 있다) 그러면 UTF-8에서 저장된 3바이트를 16진수로 바꿔보자. 0xEA 0xB3 0x84가 된다. 다음, '정'의 코드포인트는 U+C815이다. 아까와 같이 UTF-8인코딩을 해보면 11101100 10100000 10010101이 되고, 이는 16진수로 0xEC 0xA0 0x95가 된다. 위의 것과 합치면 총 6바이트이다. 한 번 나열해보자.

0xEAB3 0x84EC 0xA095

한국어 문자셋은 2바이트로 한 글자를 만들기 때문에 위의 6바이트로는 총 세 글자를 만들 수 있다. 그 세 글자는 아마 '怨꾩젙'이 될 것이다. unicode.org에 접속하면 각 글자의 코드포인트는 알 수 있지만 그 글자의 한국어 문자셋 번호는 알 수 없다. Windows XP에서 쓰는 한국어 문자셋은 정확히 말하면 코드페이지 949(cp 949)이다. 다행히 unicode.org에 한글 각 자(字)에 대해서 코드포인트와 문자셋 번호를 함께 적어 놓은 문서가 있다. 아래의 표를 보자. 위에서 찾은 2바이트 16진수에 대응하는 코드포인트와 글자가 보이는가. 예상대로 위 문자셋에 대응하는 글자는 '怨꾩젙'이다.

*cp949 to Unicode table (일부)

(설명)
1열: 한국어 문자셋 (cp 949)
2열: 유니코드 코드포인트
3열: 글자
---------------------------------------------------------------------------
0xEAB3 U+6028 #CJK UNIFIED IDEOGRAPH -> 怨
0x84EC U+AFA9 #HANGUL SYLLABLE SSANGKIYEOK YO RIEULTHIEUTH -> 꾩
0xA095 U+C819 #HANGUL SYLLABLE CIEUC EO THIEUTH -> 젙
---------------------------------------------------------------------------
(출처)
1: http://www.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/CP949.TXT
2: http://www.unicode.org/charts/PDF/U4E00.pdf

이 제 유니코드, 인코딩 등에 관한 개념이 잡히기 시작할 것이다. '조엘 온 소프트웨어'에도 나와 있듯이 텍스트를 전송할 때에는 텍스트뿐만이 아니라 텍스트가 기록된 방식까지 전송해야 한다. 송신자의 컴퓨터와 수신자의 컴퓨터가 서로 다른 텍스트 인코딩 방식을 사용할 경우 텍스트를 제대로 처리할 수 없기 때문이다. 두 가지 다행스러운 점은 영어로 문서를 주고 받을 경우 어떤 인코딩 방식이든 동일하게 원하는 결과를 얻을 수 있다는 것과 유니코드가 점점 더 보편화되고 있다는 것이다. 앞으로 문서를 작성할 때 유니코드를 사용한다면 전 세계 어느 컴퓨터에서도 제대로 처리할 수 있을 것이다. (이미 Windows XP는 유니코드를 기본 인코딩 방식으로 사용하고 있지 않은가)

PS. 사실 유니코드에 대한 설명 부분이 많이 부실하다. 유니코드에서는 각 나라 언어에서 쓰이는 글자들을 plane이라는 몇몇 그룹으로 묶어 놓았다. 총 17 plane이 존재한다. 그 중 컴퓨터 세계에서 자주 쓰이는 언어들을 모아 0번째 plane이라 이름 붙였는데 다른 말로 BMP(Basic Multilingual Plane)라고 한다. 이 BMP에 속하는 모든 언어를 표현하기 위해서는 최대 3바이트가 필요하다. UTF-8을 쓸 경우 한글은 3바이트를 모두 사용한다. 그 이유는 앞에서 설명했듯이 각 바이트마다 코드포인트가 아닌 다른 정보를 넣어야 하기 때문이다. 그 외에도 자세히 파고들면 틀린 얘기들이 본문에 많이 있을 수 있다. 이 글 뿐만 아니라 다른 분들의 글들도 읽어볼 때 비로소 이 주제에 대한 정확한 지식을 얻을 것 같다.

참고문헌:
Programming Windows, Charles Petzold, 5th edition, 1999.
조엘 온 소프트웨어, 조엘 스폴스키 (박재호, 이해영 역), 2005.
API로 배우는 Windows 구조와 원리, 야스무로 히로카즈 (김용준 역), 2004.
텍스트와 이미지 처리 중심의 멀티미디어 입문, 양단희, 2006.
신고
Posted by 타임워커™
TAG ,


티스토리 툴바