IT 이야기/유니코드2009. 6. 12. 16:14

UTF 얘기는 이미 충분히 글을 적었음에도 다시 포스팅을 하는 이유는 사람들이 자주 헛갈리는 캐릭터셋(charset)과 인코딩(enecoding)의 차이를 이야기 하기 위해서이다. 

"A"라는 글자가 컴퓨터에 이진수로 표현되어 저장된다는 것은 누구나 알고 있을 것이다. 중요한건 2단계를 거치는 것이 중요하다. 첫번째는 "해석"이고 두번째가 "저장"이다. 

첫번째 "해석"이란 컴퓨터가 아닌 사람을 위해 존재한다. "A" 글자를 저장해야 한다고 할때 글자 "A"라는 의미를 어떻게 전달해야 할까가 문제의 시발점이다. 다른 사람에게 "A"가 어떻게 저장되지? 라고 묻는건 올바르지 않다. 좀더 정확하게 말하자면 "2009년 현재 미국에서 사용하고 있는 알파벳의 대문자 A"라고 전달해야 한다. 번거롭기 그지 없다. 게다가 그 다른 사람이 사는 문화권에서는 "에이" 라고 불리는 다른 문자가 있을지도 있을지도 모른다. 원래 말이라는건 오해하기 쉬운 법이다. 

그래서 좀더 쉬운 전달을 위해 모든 문자에 숫자를 할당했다.(숫자은 전세계 모든 사람의 공용어 역할을 한다.) 이제 다른 사람에게 (십진수로) 65(16진수로 표현하면 0x41)번 문자는 어떻게 저장하지? 라고 물으면 된다. 이렇게 해석단계에서 사용하는, 문자에 번호를 매겨놓은게 charset (캐릭터 셋)이다. 컴퓨터가 발명된 초기부터 이렇게 별도의 해석 단계가 있었던건 아니었다. 컴퓨터가 처음 발명된 초기에는 해석 == 저장이었기 때문에 65번 글자인 'A'는 65번으로 저장한다 였다. 초기에는 128개(2^7)에만 번호를 할당했고 저장하였는데 구미지역에서는 이정도면 충분하였다. 

다시 말해서 캐릭터 셋은 해당 캐릭터 셋이 표현가능한 문자의 일종의 단순한 매핑 테이블이다. 이를테면 한글 "가"라는 글자는 KSC5601에서 "0116" 번으로 할당되어 있다. 이제 "0116" 에 해당하는 글자(즉 한글 "가")를 어떻게 컴퓨터의 이진 코드화 시키는가가 인코딩이다. 앞서 해석 - 캐릭터셋에 매핑된 숫자를 읽기 -는 논리적이며 저장 - 인코딩 -은 물리적 과정이기 때문에 서로 같지 않고 당연히 "0116" 글자가 0116 라고 저장되리라는 것을 기대하거나 보장할 수 없다. 

왜냐하면 캐릭터 셋은 논리적 과정이라 얼마든지 새로운 캐릭터 셋을 만들어도 상관이 없지만(물론 이 경우 다양한 단체의 알력싸움에 의해 정해진다.) 인코딩은 물리적 단계이며 이경우 가장 중요한 것은 호환성이다. 예컨데 "A"라는 글자는 KSC5601에서 "3305"번에 할당되어 있는데 디코딩은 인코딩의 역함수이기 때문에 기존에 ASCII로 "0x40"으로 저장된 코드를 "A"라고 읽을 수 없다. 따라서 캐릭터 셋의 번호대로 인코딩이 되지는 않고 실제로는 캐릭터셋의 해쉬 함수 인코딩을 하게 된다. 

KSC5601의 해쉬 함수를 통해 (KSC5601은 일반적으로 캐릭터셋의 의미를 가지지만 때로는 인코딩을 의미하기도 한다. 그래서 이전의 책이나 글에서는 문맥을 통해 구별하는 수밖에 없으며 이는 많은 혼란의 요인이 되었다.) "0116"글자는 "0xAC00"로 인코딩(즉 computer에는 AC00로 저장이 된다.) "3305" 글자는 "0x40"으로 바뀌어서 저장이된다. 문제는 디코딩을 할때 "0xAC00"  코드를 읽어서 화면에 "가"라고 보여줄 수 있느냐이다. 왜냐하면 파일에는 해당 파일의 캐릭터 셋에 대한 정보를 저장하기 않기때문에 이 파일을 읽을때 "0xAC00" 가 정말 "가"인지를 확인할 수 없기 때문이다. 어쩌면 다른 캐릭터 셋의 인코딩으로 "0xAC00"는 다른 글자일지도 모르기 때문이다. (어쩌면 초기에 구미에서 컴퓨터를 발명하면서 파일에 캐릭터 셋을 저장하지 않는 것이 문제의 시발점인지 모른다. )

파일을 인코딩한 해쉬 함수의 역함수는 당연히 캐릭터 셋에 종속이 되기 때문에 해당 파일의 캐릭터 셋을 모르고서는 해당 파일이 제대로 읽을 수 없다. 앞문장의 "제대로" 라는 뜻은 "0xAC00" 라는 코드를 읽어도 해당 파일의 캐릭터 셋을 알지못하면 이를 "가"로 제대로 화면에 보여주지 못한다는 이야기 이다. 

만약 자신의 컴퓨터에서 혼자만 쓰는 파일이라면 상관이 없다. 각 컴퓨터에는 기본 캐릭터셋이 지정되어 있기 때문에 아무런 추가 작업을 하지 않는 이상 기본 캐릭터 셋으로 쓰고 기본 캐릭터 셋으로 읽으면 된다. 그러나 A 컴퓨터에서 작성한 파일을 B 컴퓨터로 전달하는 경우(이메일을 쓰거나 웹에 글을 올리거나 하는 경우도 마찬가지이다. )에 해당 파일이 어떤 캐릭터 셋인지 전달해 주지 않으면 상대편의 컴퓨터에서는 제대로 읽을수가 없다. 설사 말로 알려준다고 하더라도 상대편의 컴퓨터에 해당 캐릭터셋에 대한 정보가 없으면 역함수가 없고 디코딩도 당연히 할수 없다. 

그럼 이쯤에서 나올만한 생각이 있다. 지구의 모든 컴퓨터가 공용으로 사용할 수 있는 캐릭터 셋을 만들면 되지 않을까? 정답이다. 그래서 나온게 유니코드이다. 문제는 유니코드의 발상이 나오기 전에 이미 많은 캐릭터 셋이 많은 컴퓨터에서 사용이 되고 있다는 점과 모든 글자를 담기 위해서는 글자당 할당되는 번호가 길어지고 이는 당연히 저장 공간이 길어지는 2가지 문제가 추가적으로 야기된다. 

둘을 묶어 보면 기존에 호환성을 유지하면서도(여기서 호환성이란 보통 ASCII만을 의미한다.) 수많은 글자를 가능한 작은 저장공간에 인코딩을 할 수 있어야 한다는 얘기이다. 


ASCII
당시의 컴퓨터는 유닉스 기반의 컴퓨터로 7비트가 1바이트인 메모리를 사용하였고 따라서 자연스럽게 하나의 문자를 표현하는데 7비트를 사용하였다. null로 시작하는 32개의 제어문자,공백문자, 94개의 프린트문자, 지움문자로 128개의 비트조합을 배정하였다. 이에 따라 1963년 최초의 ASCII 표준이 제정되었는데 이때까지만 해도 많은 비트 조합이 94개의 프린트 문자 번호로 배정되지 않은 상태였으며 1968년에 오늘날과 같은 ASCII 코드가 만들어져 표준으로 지정되었다. 


ISO 8859
같은 라틴계열의 문자이긴 하지만 별도의 강세문자를 가지는 프랑스나 그리스의 문자는 구미의 알파벳과 조금 달랐고 이런 언어의 표현을 포함하는 캐릭터 셋을 만들려는 국제적인 노력은 ISO8859 시리즈에서 나타났다. ISO 8859-1은 서유럽 언어를 다루기에 충분했으며, ISO 8859-7은 기본적인 그리스 문자, 알파에서 오메가, 발음기호 등 현대의 그리스 문자와 영어를 모두 지원했다. ISO 8859에서는 하나의 문자를 표현하는데 8비트를 사용하며 ASCII 외의 각 나라마다 자신이 사용할 문자는 128 이후에 배치하였다. 즉 ISO 8859는 128개의 세계 공통 문자(주로 알파벳과 숫자, 제어코드)와 128개의 지역 문자(지역별로 다른 문자 할당)의 조합이다. 

ISO 2022
상식적으로 공통으로 사용하는 128개의 문자말고 추가적인 128개의 문자는 지역마다 다르게 정의되었기 때문에 제대로된 문서 교환이 이루어질리 없다. 파일에는 그 파일이 어떤 캐릭터 셋을 사용했는지에 대한 정보가 저장되어 있지 않기 때문에 wrirte할때는 불어 지역문자를 사용하면 러시아에서 read 할때는 제대로 읽혀지지 않는다. 초기에는 네트워크가 활발하지 않았고 대부분 컴퓨터에는 혼자 사용하는 것이라는 인식이 강했지만 이게 문제가 되는 대표적인 예는 이메일(Email)이다. 

프랑스 사람이 러시아 사람에게 프랑스어로 이메일을 작성했을때 러시아인 컴퓨터에서 프랑스어가 제대로 보이기 위해서 이메일은 이스케이프 시퀀스(escape sequence)로 글자별로 캐릭터 셋을 설정하도록 하였다. 즉 프랑스 이메일 클라이언트는 프랑스어 코드가 나올때마다 ISO 2022 문자 인코딩들은 이어서 나오는 문자들에 대한 문자세트를 지시하는 escape sequence를 포함하고 있다. 그럼 저장단계에서 escape를 보고 해당 캐릭터셋의 번호로 저장 하였다. 즉 아직까지는 해석과 저장의 명확한 분리를 하지 않았기 때문에 기본 ASCII가 아닌 문서를 교환하는 것은 이렇게 비효율적인 면이 존재한다. (escape 문자로 인해 data 길이가 늘어나고 여전히 read하는 곳에서 해당 charset을 인식하지 못한다면 읽을 수 없었다.)

ISO 2022 문자세트들은 여전히 많이 사용되고 있으나, 최근에는 최신 이메일 소프트웨어 등 에서 UTF-8과 같은 유니코드 문자 인코딩들을 사용하는 것으로 차츰 변환되고 있다.


KSC 5601

KSC 5601은 94x94의 각 위치(행열)에 한글 문자를 일정한 순서에 따라 배열해 놓은 charset이다. 앞서 말했듯이 한글은 표의문자와 표음 문자 2가지 성격을 모두 가지고 있는 독특한 특성때문에 여러가지 다양한 방법중에서 한글 코드의 KS 제정에서 완성형이 채택된 것은 내부적으로 한글의 출력이 모아쓰기 형태로 이루어지면서 동시에 한자를 섞어서 쓸 수 있어야 한다는 사회적 요구로 조합형을 수용 하기가 어려웠기 때문이다.(물론 정치적인 이유가 없던것은 아니다.)

또 다른 배경은 국가간의 정보교환을 위한 코드 표준화 과정에서 앞의 ISO 2022에서 제정한 코드 체계에 따라 세계 각국의 문자를 처리하는데 기인한다. 이는 1바이트 코드로 한 문자 표현이 불가능한 CJK(Chinese, Japanese, Korean) 문자를 2바이트 코드 영역의 첫 번째 영역에 넣을 수 있도록 영역을 확보해야 했기 때문이다.


KSC 5601은 완성형 한글 2,350자, 한자 4,888자, 기술/학술기호 등 특수문자 432자, 숫자 30자, 한글 낱자 94자, 로마문자 52자, 그리스 문자 48자, 괘선 조각 68자, 라틴 문자 27자, 일본 문자 169자, 러시아 문자 66자 등 총 8,224자와 기타 사용자 정의 영역으로 한글 96자, 한자 95자 정도를 사용하도록 배정하고 있다.(이후 KSX 등의 명칭이 변동된 역사는 이전글을 참조)

를 보면 94*94(8836) 의 매트릭스에 위 문자들이 지정되어 있다. 'A'가 03 * 33에 'a'가 03*65에 지정되어 있고 '가'는 16*01에 할당되어 있다. 위 PDF를 보면 캐릭터 셋과 인코딩의 차이에 대해 좀더 이해할 수 있다. KSC 5601 캐릭터 셋이란 "한국"이라는 지역에서 최소한 지원해야 하는 문자들에게 각각의 번호를 지정해놓은 것이고 인코딩이란 그 번호들을 컴퓨터 이진수로 어떻게 저장할 것인가에 대한 문제이다. 

일반적으로 KSC 5601을 지원하는 인코딩은(이를테면 euc-kr)은 1byte의 첫번째 비트가 0이면 이후 7bit를 ASCII문자에 대응시키고 첫번째 bit가 1이면 다음 바이트까지 묶어서 KSC 5601의 문자번호를 지정된 해쉬함수 계산을 통해 저장된 문자로 인식한다. 

네트워크가 발전하고 CJK에 컴퓨터가 많이 보급되면서 위와같이 지역적인 문사셋을 사용하는 것은 글자깨짐의 문제(파일의 메타정보에는 문자셋을 지정할 수 없다는 것을 기억하자. 대표적으로 HTML안에도 HTML의 문자셋을 HTML 문자 안에 지정해야 한다. 이러한 - 파일 해석을 위한 방법이 파일안에 있는 - 방법이 먹혀드는 이유는 HTML은 규약상 charetSet을 지정하는 부분까지 ASCII를 제외한 다른 문자가 나오지 않아야 한다는 가정때문이다.)때문에 UniCode가 나왔다. 


UNICODE

유니코드(Unicode)는, 컴퓨터에 저장하려는 모든 문서의 글자에 대해 캐릭터 셋을 제공하기 위한 국제 표준이다. 유니코드는 오늘날 실제 사용되는 모든 문자들과, 학자들만 사용하는 문자들, 또 수학기호, 언어학기호, 프로그래밍 언어 기호 등까지 포함하고 있다. 보통 유니코드는 말하거나 문서에 적을때 캐릭터 셋과 인코딩의 두가지 의미를 동시에 가지기 때문에 다소 헛갈리지만 

보통의 경우 
유니코드라고 말하면 캐릭터 셋을, 
USC-2, UCS-4는 캐릭터 셋 혹은 인코딩 2가지 의미를
UTF-8, UTF-16, UTF-32라고 말할때는 인코딩 방법을 의미한다. 

UCS-2는 2byte 숫자로 전세계에서 자주사용하는 문자를 지정해놓은 캐릭터 셋이고(여기에는 기본 ASCII 와 서유럽언어, CJK 언어 일본어 등이 할당되어 있다. 단 65536의 제약이 있기 때문에 모든 글자가 할당되어 있지는 않다.) 이 캐릭터 셋의 번호로 컴퓨터에 저장하면 UCS-2 인코딩을 사용한 경우가 된다. 

USC-4는 4byte의 숫자로 전세계의 모든 문자와 학자들만 사용하는 문자들, 수학기호, 언어학기호, 프로그래밍 언어등까지 포함하고 이후에 새로이 나타나게 될지도 모를 문자들를 위해 많은 여유공간이 있다. 실제로는 0번부터 256^4 까지 순차적으로 번호를 부여하는게 아니라 32bit를 영역별로 쪼개서 언어판(Plane)과 Group를 지정한다. ( Group 1byte + Plane 1byte + CodePoint 2byte를 사용한다. UCS-4가 인코딩의 의미로 사용될때에는 0x00000000 ~ 0x0010FFFF 범위만을 합법적인 코드값으로 갖는다. 00그룹 + (00 - 10 까지의 17개 Plane) + codepoint 2byte)


인터넷에서는 카더라 통신이 많아서 혼란의 소지가 많지만. 위 문서는 유니코드에 대해 가장 잘 설명한 그리고 정확한 문서이다. 

'IT 이야기 > 유니코드' 카테고리의 다른 글

Unicode와 Database  (0) 2009.03.01
Global Software - Unicode와 Programming  (0) 2009.02.26
Global Software - Unicode  (0) 2009.02.25
Global Software  (0) 2009.02.22
Posted by bleujin