UTF8 한글 문자열을 첫가끝 낱자(자소)로 분해하기
Posted in Programming, 컴퓨터와 인터넷 on 2009/08/20 by terzeron유니코드(Unicode)에 정의된 한글은 기본적으로 완성형을 따른다. 다시 말해서 초성/중성/종성이 합쳐져 있는 글자 하나씩을 코드셋(codeset)에 저장한 것이다.
그러나 다행히도 예전의 KSC5601 완성형이나 MS가 정의한 확장완성형(UHC, CP949)과는 달리 조합의 원칙에 따라 인코딩되어 있으므로 첫가끝(초성/중성/종성) 낱자, 다시 말해 한글 자소로 분해할 수 있다.
인터넷에서 찾아보니 이 기능을 위해 여러가지 꽁수나 매핑 테이블을 이용해서 구현해놓은 것들이 많은데, ICU 프로젝트에서 제공하고 있는 라이브러리를 사용하면 아주 간단하게 자소로 분해하는 기능을 얻을 수 있다.
#include#include #include #include #include "unistr.h" #include "normlzr.h" #include "unorm.h" using namespace std; int decompose(const char* text, wchar_t* wcs_buf, uint buf_size) { // UTF-8 to UCS4 UnicodeString str = UnicodeString::fromUTF8(StringPiece(text)); // UCS4 to NFD UnicodeString result; UErrorCode status = U_ZERO_ERROR; Normalizer::normalize(str, UNORM_NFD, 0, result, status); if (U_FAILURE(status)) { cerr << "can't decompose a UTF8 string, " << status << ": " << u_errorName(status) << endl; return -1; } result.toUTF32((UChar32*) wcs_buf, buf_size, status); return 0; } int main(void) { const char* text = "한글"; wchar_t wcs_buf[1024]; decompose(text, wcs_buf, sizeof (wcs_buf)); for (uint i = 0; wcs_buf[i] != 0; ++i) { cout << "wcs_buf[" << i << "]=0x" << hex << (int) wcs_buf[i] << endl; } cout << endl; return 0; }
ICU project에서 ICU4C 라이브러리를 다운로드한다.
/home/terzeron을 라이브러리 설치 디렉토리로 가정한다.
$ configure --prefix=/home/terzeron && make all install
$ g++ -c comp_test.cc -I/home/terzeron/include -I/home/terzeron/include/unicode -g -Wall $ g++ -o comp_test.cc -L/home/terzeron/lib -licuuc -licudata comp_test.o ./comp_test
낱자를 구하는 것이 무슨 의미가 있을까? 낱자를 구하게 되면 보다 정확한 한글 단어 간의 거리(edit distance)를 구할 수 있고, 단어 간 거리를 알면 오타/정자 변환이 좀 더 용이해지며, 단어들을 클러스터링하기도 쉬워진다.
UTF-8 문자열 바이트 스트림이나 UCS4 문자열 바이트 스트림을 가지고 비교해도 단어 간 거리를 구할 수 있으나 자소 단위의 미묘한 차이를 발견하는 게 아니라 글자 단위의 거리가 되므로 이 방법은 자소를 이용한 거리계산 방법에 비해 부정확할 수 밖에 없다. 그러나 이 자소를 이용한 방법이 100% 정확한 것은 아니다. 자소 뿐만이 아니라 두벌식 자판이나 세벌식 자판에서 키 배치에 따라 자소 간의 거리를 따로 정의함으로써 보다 정확한 오타/정자용 거리를 계산할 수도 있다. 그러나 자소를 이용한 방법으로도 충분한 결과를 얻을 수 있다.
이전 글 "한글 검색어 간 유사도를 위한 Levenshtein distance 함수"을 참고하면 자소 단위의 한글 단어 간 거리(유사도)를 계산할 수도 있다.