by BLUEnLIVE | 2010/09/24 09:30
아이폰은 단점이 없는 완벽하고도 지고지순한 폰이 아니다. 철학이 뚜렷하고, 이에 따른 장단점이 명확히 나뉘는 폰이다. 그런데, 그런 원인...
1. 유니코드의 한글자소는 초중종성 정보가 있는 것과 없는 것이 별도로 존재
유니코드에는 (당연히) 음절 단위의 글자 외에도 한글자소가 별도로 존재한다.
그런데, 이 자소에는 초중종성의 정보가 있는 자소와 없는 자소가 별도로 존재한다.
일단, 정보가 있는 자소는 U+1100 부터 시작된다.
현대어→고어 순으로 할당되어 있으며, 현대어에는 ㅄ같은 문자가 초성에 할당되어있지 않았다.
초중종성 정보가 없는 자소는 U+3131 부터 시작된다.
여기는 자음에 초성과 종성이 혼합되어 있으며, 이 순서는 완성형 한글의 순서와 정확히 일치한다.
그런데, 이 자소에는 초중종성의 정보가 있는 자소와 없는 자소가 별도로 존재한다.
일단, 정보가 있는 자소는 U+1100 부터 시작된다.
현대어→고어 순으로 할당되어 있으며, 현대어에는 ㅄ같은 문자가 초성에 할당되어있지 않았다.
초중종성 정보가 포함된 한글자소: U+1100부터 시작됨. 아래 표시된 부분은 종성 'ㄱ'
초중종성 정보가 없는 자소는 U+3131 부터 시작된다.
여기는 자음에 초성과 종성이 혼합되어 있으며, 이 순서는 완성형 한글의 순서와 정확히 일치한다.
2. 두 종류의 자소(U+1100, U+3131)를 완성형으로 변환시 문제 발생 가능
VC6은 기본적으로 유니코드가 아닌 완성형 코드를 지원한다.
그리고, 시스템에서 이를 유니코드로 변환할 때는 U+3131로 변환한다.
즉, 아래와 같은 코드를 실행시켰을 때...
c:\ㅁㅏㄹㄷㅗㅇㅏㄴㄷㅙ.txt가 존재하더라도 한글자소가 U+1100으로 저장되어 있다면 rename되지 않는다.
왜냐하면 _trename()의 내부에서는 이런 순서로 진행되기 때문이다.
API: U+1100 → finder.GetFilePath(): 완성형 변환 → _trename(API): U+3131 변환
따라서, 멀쩡히 있는 파일명을 API를 통해 읽은 뒤 다른 이름으로 바꾸는 작업이 불가능할 때도 있는 것이다.
물론, 해결책은 있고, 간단하다. 컴파일러를 유니코드 모드로 설정하면 된다.
그리고, 시스템에서 이를 유니코드로 변환할 때는 U+3131로 변환한다.
즉, 아래와 같은 코드를 실행시켰을 때...
CFileFind finder;
BOOL bOk = finder.FindFile(_T("c:\\*.txt"));
while (bOk)
{
bOk = finder.FindNextFile();
if (finder.IsDots() || finder.IsDirectory()) continue;
_trename(finder.GetFilePath(), _T("c:\\말도안돼.txt"));
}
c:\ㅁㅏㄹㄷㅗㅇㅏㄴㄷㅙ.txt가 존재하더라도 한글자소가 U+1100으로 저장되어 있다면 rename되지 않는다.
왜냐하면 _trename()의 내부에서는 이런 순서로 진행되기 때문이다.
API: U+1100 → finder.GetFilePath(): 완성형 변환 → _trename(API): U+3131 변환
따라서, 멀쩡히 있는 파일명을 API를 통해 읽은 뒤 다른 이름으로 바꾸는 작업이 불가능할 때도 있는 것이다.
물론, 해결책은 있고, 간단하다. 컴파일러를 유니코드 모드로 설정하면 된다.
3. 유니코드 한글은 조합형으로 구성되었음
한글을 조합하는 방법에 대해 이리저리 고민했는데, 알고보니 유니코드의 한글 코드는 조합형으로 구성되어있다.
보통 조합형 한글이라는 개념은 2바이트(16비트)를 1비트(무조건 1)+5비트(초성)+5비트(중성)+5비트(종성)으로 구성하는 방식을 의미한다.
하지만, 유니코드의 한글은 이런 비트를 조합하는 방식은 아니다. (그런 테이블을 할당받을 수도 없음)
U+AC00부터 초성 19자, 중성 21자, 종성 28자를 순서대로 배치하는 것이다.
예컨데, 뷁이라는 글자의 코드는 U+AC00 + 7(ㅂ)*21*28 + 15(ㅞ)*28 + 9(ㄺ) = U+DBC1이다.
이러한 원리를 이용해서 간단한 식만으로 한글을 조합하거나, 자소를 분리해낼 수 있는 것이다.
보통 조합형 한글이라는 개념은 2바이트(16비트)를 1비트(무조건 1)+5비트(초성)+5비트(중성)+5비트(종성)으로 구성하는 방식을 의미한다.
하지만, 유니코드의 한글은 이런 비트를 조합하는 방식은 아니다. (그런 테이블을 할당받을 수도 없음)
U+AC00부터 초성 19자, 중성 21자, 종성 28자를 순서대로 배치하는 것이다.
예컨데, 뷁이라는 글자의 코드는 U+AC00 + 7(ㅂ)*21*28 + 15(ㅞ)*28 + 9(ㄺ) = U+DBC1이다.
이러한 원리를 이용해서 간단한 식만으로 한글을 조합하거나, 자소를 분리해낼 수 있는 것이다.
유니코드의 각국어 할당표를 만드는 과정에서 여러나라들의 수많은 알력이 있었다.
유니코드의 한글구성표를 만드는데 노력하시고, 박터지게 싸우신 모든 분들께 감사드린다.
덧. VC++ 6.0도 유니코드를 기본으로 사용할 수 있음
메뉴에서 Project → Settings... 선택한 뒤, C/C++ 탭에서 Preprocessor definitions:를 찾는다.
여기서 _MBCS를 찾아 _UNICODE로 바꾼다.
다음으로, Link 탭에서 Output을 선택한 뒤 Entry-point symbol:을 wWinMainCRTStartup으로 지정한다.
여기서 _MBCS를 찾아 _UNICODE로 바꾼다.
다음으로, Link 탭에서 Output을 선택한 뒤 Entry-point symbol:을 wWinMainCRTStartup으로 지정한다.
예전에 한컴 간담회에서 CTO 님(!)이 한국 유니코드 조직위원회 회원이신가 그러셔서
답글삭제조합형 유니코드 체계를 넣기위해서 엄청나게 고생하셨다고 하시더라구요.
@구차니 - 2010/09/26 18:42
답글삭제몇몇 분 성함을 듣기는 했는데, 확실한 정보를 다 찾지 못해 실명 언급은 피했습니다만, 관여하신 모든 분께 감사드릴 뿐입니다.
알고 계시는 것도 있고 아닌 게 있을 수도 있지만 보시는 분들 참고 삼아 덧글로 적어 봅니다.
답글삭제1. 초성/중성/종성 자모를 '한글 자모', 그냥 자모를 '한글 호환 자모'라고 합니다.
전자는 '첫가끝 자모'라는 애칭으로 더 많이 불립니다. 첫가끝 자모는 이후에도 여러 번 개정되어,
2007년 4월부터 옛한글을 유니코드만으로 완벽하게 재현할 수 있게 되었습니다.
2. '한글 자모' 대 '한글 호환 자모' 테이블이 있고,
조합된 '한글 자모'를 완성형으로 바꿔 주는 로직도 있습니다.
지금 찾기는 힘드네요. ㅎ
3. 유니한글은 원칙상 '완성형'입니다.
그러나 '완성형'은 대개 X1001이나 X1003 혹은 CP949를 이르기 때문에 정확한 용어는 없습니다.
또, 유니코드에서 한글 조합형이란 '한글 자모'를 첫-가-끝 순으로 배열한 것을 의미합니다.
참 완성형 11172자를 순서대로 받느라 유니코드 BMP의 65536자 중에서 우리가 먹은 게(...) 많죠.
집어넣으려고 애쓰신 분들 정말 고생하셨습니다. 보이지 않는 국가적 은인들이세요.
@Un-i-que - 2010/09/29 23:13
답글삭제첫가끝이라는 용어에 대해 좀 더 설명해주시면 안될까요?
@BLUEnLIVE - 2010/09/29 23:16
답글삭제별 건 아니고 '첫소리', '가운뎃소리', '끝소리'입니다. ㅎㅎ