유니코드 한글의 각 음소를 분리하기

유니코드에서 한글은 0xAC00에서 0xD7A3 사이의 코드 값을 갖는다. 각 16진수값은 10진수로 표시하면 44032와 55203으로 총 11,172개이다. 유니코드 내 한글은 초/중/종성의 각 음소의 조합으로 표현된다. 즉 초성 19개, 중성 21개, 종성 28개를 조합하여 하나의 글자가 되는 것이다. 따라서 각 초,중,종성의 위치값을 계산하여 최종적으로 만들어지는 글자의 코드가 생성된다. 이 때 들어가는 값은 위치 값으로 0~해당 음소의 개수-1 만큼의 인덱스를 의미한다.

((초성 * 21) + 중성) * 28 + 종성 + 0xAC00

이를 역산하면 어떤 문자의 코드값으로부터 각 음소의 인덱스를 구할 수 있다.  즉 각 음소 중에서 몇 번 째 글자인지를 알 수 있게 된다.

초성 = ((문자코드 – 0xAC00) / 28) / 21
중성 = ((문자코드 – 0xAC00) / 28) % 21
종성 = (문자코드 – 0xAC00) % 28

이 때 계산된 값은 각 음소가 음소 문자 중에서 몇 번째 문자인지를 나타내는 위치값이다.
초성의 자모 코드 시작값은 0x1100, 중성은 0x1161, 종성은 0x11A8 이므로 이를 각각 더한다. 특히 종성이 없는 경우가 있기 때문에 종성에는 1을 뺀다.

초성의 자모코드 = 초성인덱스 + 0x1100
중성의 자모코드 = 중성인덱스 + 0x1161
종성의 자모코드 = 종성인덱스 + 0x11A8 – 1

구현

NSString에서 문자열 내 특정 글자를 뽑아오는 일은 characterAtIndex: 메소드를 사용하고 이 때 반환되는 값은 unichar 포맷이 된다. (unichar 는 unsigned short 타입의 변수형이다.)

unichar oneCode = [hangul characterAtIndex:i];

이를 위 과정을 통해 계산해서 초성 (및 중/종성)을 추출한 다음, 이를 다시 NSString으로 만들기 위해서는 stringWithFormat: 메소드를 사용한다. 이 때 포맷팅 파라미터는 %C (대문자)를 사용한다. 소문자 %c를 쓰는 것은 char 타입일 때 이다. (바꿔써도 무리는 없는 것 같더라)

코드

-(NSString *)getFirstCodeWithString:(NSString *)hangul
{
    NSString *result = @"";
    for ( int i=0; i<[hangul length];i++) {
        unichar oneCode = [hangul characterAtIndex:i];
        // 한글일 때만 처리한다.
        if ( oneCode >= 0xAC00 && oneCode <= 0xD7A3 ) {
            unichar firstCode = ((oneCode -0xAC00) / 28)/21;
            firstCode += 0x1100;
            result = [result stringAppendingString:[NSString stringWithFormat:@"%C",firstCode]];
        }
    }
    return result;
}