으아… 이 얼마만의 블로그 포스트인지 모르겠네요 :) 그동안에 졸업과 첫 직장생활에서의 자리잡기 등 일들이 많이 있었습니다. 그리고 어느새 뭔가 대단한 포스트, 멋진 포스트를 쓰고 싶어서 괜한 부담감에 쉽사리 글을 쓰지 못하고 있었는데요.. 처음 취지와 너무나도 달라진 것 같아서, 그리고 또 쓰다 보면 좋은 글도 있고 별로 시덥잖은 글도 있다고 생각해서 다시금 마음을 다잡고 쓰려고 합니다 :) 어쨌든 이제는 정말 제가 쓰고 싶은 포스트 위주로 써나가리라 다짐했습니다!

그 첫번째로 의전에서 혁신적인 생각을 가지고 살아가는 친한 형에게서 초성검색과 관련한 작업을 의뢰받았습니다. 어떤 정답도 없고, 저도 한글을 다뤄본 적도 처음이고, 모든 것이 제가 만들고 알아가야할 부분이어서 많이 미숙하겠지만, 그래도 읽어보시면서 많은 의견들 주시고, 또 더 좋은 방법이 있다면 알려주시면 감사하겠네요 :)

제가 찾아낸 아주 좋은 블로그가 있습니다. 한글 초성검색 관련 블로그
이곳에서 많은 영감을 얻었는데요, 초성처리와 관련한 규칙성 등을 알기 쉽게 설명해 주셔서 감사했습니다 :)

먼저, 대부분의 프로그래밍 언어는 ascii(아스키) 코드를 기반으로 합니다. 영어를 베이스로 하기 때문에 어쩔 수 없는 차별(?) 이겠죠? ㅎㅎ 그런데 어차피 세계에는 수 많은 언어와 문자들이 있기 때문에 256개의 문자만 지원하는 ascii로 표현하는 건 애시당초 불가능합니다. 따라서 이를 보완하기 위해서 유니코드(unicode)가 국제 표준으로 제정되고 사용되고 있는데요, 파이썬에서는 문자열 앞에 u를 붙임으로써 unicode임을 나타낼 수 있습니다.

text = u"사랑"
print text
#사랑

해당 유니코드가 숫자로 환산되면 어떻게 되는지는 아래와 같이 쉽게 확인이 가능합니다.

ord(u"ㄱ"), hex(ord(u"ㄱ"))
#(12593, '0x3131')

ord함수는 해당 문자를 십진수로 표현하는 것이고, hex를 이용하여 이를 16진수로 표현이 가능합니다.

그러면 이제 여기서 1씩 더해가면 어떤 일이 벌어질까요??

print u"\u3131", u"\u3132", u"\u3133", u"\u3134"
# ㄱ ㄲ ㄳ ㄴ

어라!? 저 위에 “ㄳ”가 보이시나요? 우리가 상식적으로 생각했을 때에 저런 자음을 실제 글에서 볼 리가 없겠죠? 그렇다면 이렇게 불규칙한 상황은 좀 난감합니다.. 그런데 다행히도 위의 0x3131로 시작하는 문자는 우리가 키보드로 눌렀을 때의 나타내지는 자음들이고, 실제로 한글 초성들을 표기하는 유니코드는 따로 제정되어 있습니다.

print u"\u1100", u"\u1101", u"\u1102", u"\u1103"
# ᄀ ᄁ ᄂ ᄃ

이제 좀 익숙한 초성 배열들이 보이시죠?? 그러면 이제 완전한 규칙성을 찾아가 봅시다.

유니코드표를 참고하면 각 초성당 ‘ㅏ’를 붙인 형태들이 가장 먼저 나옴을 확인할 수 있습니다. 따라서 규칙성을 파악하기 위해서 몇 글자에 대한 정보를 출력해 봤습니다.

ord(u"가"), hex(ord(u"가"))
#(44032, '0xac00')

ord(u"까"), hex(ord(u"까"))
#(44620, '0xae4c')

ord(u"나"), hex(ord(u"나"))
#(45208, '0xb098')

ord(u"다"), hex(ord(u"다"))
#(45796, '0xb2e4')

각 숫자들간의 차이는 588임을 확인할 수 있습니다! 그렇다면 자모의 결합 가지수가 각 초성당 588가지라는 이야기일텐데요, 그러면 우리의 이론이 맞는지를 확인해 보기 위해 간단한 코드를 작성해 봤습니다.

JAMO_START_LETTER = 44032
JAMO_END_LETTER = 55203
JAMO_CYCLE = 588

for i in range(10):
    hexNumber = JAMO_START_LETTER + JAMO_CYCLE * i
    print unichr(hexNumber)

# 가
# 까
# 나
# 다
# 따
# 라
# 마
# 바
# 빠
# 사

와우! 우리의 이론이 잘 맞아 떨어짐을 확인할 수 있네요! 그렇다면 이 원리를 이용하여 이제 주어진 문장에서 초성만을 추출하는 코드를 짜 봅시다!

def isHangul(ch): #주어진 문자가 한글인지 아닌지 리턴해주는 함수
    JAMO_START_LETTER = 44032
    JAMO_END_LETTER = 55203
    return ord(ch) >= JAMO_START_LETTER and ord(ch) <= JAMO_END_LETTER

#Constants
CHOSUNG_START_LETTER = 4352
JAMO_START_LETTER = 44032
JAMO_END_LETTER = 55203
JAMO_CYCLE = 588

text = u"대한민국 만세"
for ch in text:
    if isHangul(ch): #한글인 경우에만 초성을 추출하고 그렇지 않은 경우엔 문자를 그대로 출력합니다.
        print unichr((ord(ch) - JAMO_START_LETTER)/JAMO_CYCLE + CHOSUNG_START_LETTER)
    else:
        print ch

# ᄃ
# ᄒ
# ᄆ
# ᄀ
#  
# ᄆ
# ᄉ

멋지게 성공했네요. 이제 다음 스텝으로 넘어가 더 고차원적인 것들을 다룰 준비가 된 것 같습니다. 다음에는 초성검색 관련한 알고리즘들을 생각해보고 포스팅 하겠습니다~