콘텐츠로 건너뛰기
Home » Objective-C 한글의 초성을 분리하기

Objective-C 한글의 초성을 분리하기

유니코드 한글의 코드 값 구성 원리와 이를 토대로 각 음절의 초/중/종성을 분리하는 방법은 본 블로그의 다른 글들을 참고하면 되겠다. (원래 참조했던 외부글이 있지만, 시간이 오래 지나서 그런지 삭제되었다.)

유니코드 한글에서 초성을 분리하는 일은 그리 어렵지 않은데, 중성 및 종성으로 사용되는 28자, 21자의 간격을 이용해서 한글 자모 테이블의 초성의 인덱스를 구할 수 있다.

#import <Foundation/Foundation.h>
NSString* choseongWithString(NSString* text) {
  NSMutableArray<NSString*> *array = [
           NSMutableArray arrayWithCapacity:[text length]];
  // unichar = unsigned short
  unichar c, f;
  NSString *res;
  int i;
  for(i=0;i<[text length];i++) {
    c = [text characterAtIndex:i];
    // 한글인지 코드범위 검사
    if (c >= 0xAC00 && c <= 0xD7A3) {
      // 초성자모 코드로 변경
      f = ((c - 0xAC00) / 28 ) / 21 + 0x1100;
    } else {
      f = c;
      [array addObject:[NSString stringWithFormat:@"%C", f]];
  }
  return [array componentsJoinedByString:@""];
}

여기서 한가지 문제는 위 코드로 구한 초성 값은 한글 자모의 문자라는 것이다. 한글자모의 코드가 연속되는 경우, 플랫폼에 따라서는 자동으로 합자가 생성되기도 하기 때문에, “안녕하세요”를 위 함수로 초성을 추출하면 “ㅇㄶㅅㅇ” 가 되는 문제가 있다.

이를 해결하려면 합자로 합성되는 자모 테이블이 아닌 낱자를 위한 Hangul Compatible Jamo 테이블의 코드를 사용해야 한다. 한글자모를 낱자자모로 변경하는 공식은 아직 찾아보지 않았는데, 유니코드 문자표에 따르면 해당 글자 이름을 영어로 표기하고 코드값을 표시해주고 있다. 이런 자료들을 긁어모아서 적당히 가공하면 글자이름-코드의 쌍을 얻을 수 있는데, 한글자모와 낱자로부터 코드 변환을 위한 맵을 구할 수 있다.

예를 들어 의 경우, 초성으로 쓰이는 ‘ㄱ’과 종성으로 쓰이는 이 있고, 낱자로 쓰이는 이 있다. 이 때 각각의 이름과 코드 값은 다음과 같다.

  • "CHOSEONG KIYEOK" : 0x1100
  • "JONGSEONG KIYEOK" : 0x11A8
  • "KIYEOK" : 0x3131

따라서 자모의 코드로부터 글자 이름을 구한 다음, 글자이름을 공백으로 갈라 뒤의 이름만 취해서 그 이름의 낱자의 코드를 얻으면 자모 코드와 낱자 코드를 연결하는 맵핑이 만들어진다.

Objective-C 에서는 정수-정수를 맵핑하려면 NSNumber를 사용해서 사전을 만들면 된다. 이때 코드값에 해당하는 unicharunsigned short의 별칭이므로, [number unsingedShortValue]를 통해서 NSNumber로 부터 다시 얻어낼 수 있다.

다음 코드는 거의 9년만에 다시 작성한 초성분리기 코드이다. 단일 파일로 작성했으며, 자모가 아닌 낱자의 한글 초성으로 변환한다. 시간나면 Swift 버전도 만들어봐야겠다.

// vi: filetype=objc
#import <Foundation/Foundation.h>
NSDictionary<NSNumber*, NSNumber*> * makeTransformer() {
NSDictionary<NSNumber*, NSNumber*> * dict = @{
@(0x1100): @(0x3131), @(0x1101): @(0x3132), @(0x1102): @(0x3134), @(0x1103): @(0x3137),
@(0x1104): @(0x3138), @(0x1105): @(0x3139), @(0x1106): @(0x3141), @(0x1107): @(0x3142),
@(0x1108): @(0x3143), @(0x1109): @(0x3145), @(0x110a): @(0x3146), @(0x110b): @(0x3147),
@(0x110c): @(0x3148), @(0x110d): @(0x3149), @(0x110e): @(0x314a), @(0x110f): @(0x314b),
@(0x1110): @(0x314c), @(0x1111): @(0x314d), @(0x1112): @(0x314e), @(0x1114): @(0x3165),
@(0x1115): @(0x3166), @(0x111a): @(0x3140), @(0x111c): @(0x316e), @(0x111d): @(0x3171),
@(0x111e): @(0x3172), @(0x1120): @(0x3173), @(0x1121): @(0x3144), @(0x1122): @(0x3174),
@(0x1123): @(0x3175), @(0x1127): @(0x3176), @(0x1129): @(0x3177), @(0x112b): @(0x3178),
@(0x112c): @(0x3179), @(0x112d): @(0x317a), @(0x112e): @(0x317b), @(0x112f): @(0x317c),
@(0x1132): @(0x317d), @(0x1136): @(0x317e), @(0x1140): @(0x317f), @(0x1147): @(0x3180),
@(0x114c): @(0x3181), @(0x1157): @(0x3184), @(0x1158): @(0x3185), @(0x1159): @(0x3186),
@(0x115b): @(0x3167), @(0x115c): @(0x3135), @(0x115d): @(0x3136)
};
return dict;
}
NSString* choseongWithString(NSString* text) {
NSMutableArray<NSString*> *array = [NSMutableArray arrayWithCapacity:[text length]];
unichar c, f;
NSNumber* g;
int i;
@autoreleasepool {
NSDictionary<NSNumber*, NSNumber*> *transformer = makeTransformer();
for(i=0;i<[text length];i++) {
c = [text characterAtIndex:i];
if(c>=0xAC00&&c<=0xD7A3) {
f = ((c – 0xAC00) / 28 ) / 21 + 0x1100;
g = [transformer objectForKey:@(f)];
f = g != nil ? [g unsignedShortValue] : f;
} else {
f = c;
}
[array addObject:[NSString stringWithFormat:@"%C", f]];
}
}
return [array componentsJoinedByString:@""];
}
int main(int argc, const char* argv[]) {
@autoreleasepool {
NSString *text, *result;
if (argc > 1) {
NSMutableArray<NSString*> *array = [NSMutableArray arrayWithCapacity:argc-1];
int i;
for(i=1;i<argc;i++) {
[array addObject:[NSString stringWithUTF8String:argv[i]]];
}
text = [array componentsJoinedByString:@" "];
} else {
NSFileHandle *stdin = [NSFileHandle fileHandleWithStandardInput];
NSData *data = [stdin availableData];
text = [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease];
}
result = choseongWithString(text);
printf("%s\n", [result UTF8String]);
}
return 0;
}
view raw choseong.m hosted with ❤ by GitHub