한글날에 한 포스트 작성합니다. 이 포스트는 파이썬에서 한글 완성자를 분석하는 포스트입니다.
유니코드에서 한글 완성자는 ‘가’부터 ‘힣’까지 모두 11172자가 있으며 ‘가’는 0xAC00(Dec 44032)에, ‘힣’은 0xD7A3(Dec 55203)에 배당되어 있습니다. 그리고 이는 과거에 널리 사용되었던 완성형(KS X 1001)과는 달리 DOS 시절 많이 쓰였던 조합형 코드처럼 오늘날의 한글 맞춤법 체계에서 조합 가능한 모든 글자들이 규칙적으로 배열되어 있다는 특징이 있습니다.
이 특징을 이용해서 코드를 작성해 보면 다음과 같습니다.
import re HAN_CHO = ['ㄱ', 'ㄲ', 'ㄴ', 'ㄷ', 'ㄸ', 'ㄹ', 'ㅁ', 'ㅂ', 'ㅃ', 'ㅅ', 'ㅆ', 'ㅇ', 'ㅈ', 'ㅉ', 'ㅊ', 'ㅋ', 'ㅌ', 'ㅍ', 'ㅎ'] HAN_JUNG = ['ㅏ', 'ㅐ', 'ㅑ', 'ㅒ', 'ㅓ', 'ㅔ', 'ㅕ', 'ㅖ', 'ㅗ', 'ㅘ', 'ㅙ', 'ㅚ', 'ㅛ', 'ㅜ', 'ㅝ', 'ㅞ', 'ㅟ', 'ㅠ', 'ㅡ', 'ㅢ', 'ㅣ'] HAN_JONG = [' ', 'ㄱ', 'ㄲ', 'ㄳ', 'ㄴ', 'ㄵ', 'ㄶ', 'ㄷ', 'ㄹ', 'ㄺ', 'ㄻ', 'ㄼ', 'ㄽ', 'ㄾ', 'ㄿ', 'ㅀ', 'ㅁ', 'ㅂ', 'ㅄ', 'ㅅ', 'ㅆ', 'ㅇ', 'ㅈ', 'ㅊ', 'ㅋ', 'ㅌ', 'ㅍ', 'ㅎ'] txt = input("낱자를 분석할 한글 완성자 문자열을 입력하세요: ") rtxt = re.sub(r'[^가-힣]', '', txt) # 한글 완성자만 남김 print("+----+--------+--------+-------+") print("|글자| 초중종 | Hex | Dec |") print("+----+--------+--------+-------+") for c in rtxt: cc = ord(c) - 44032 # 한글 완성자의 유니코드 포인터 값 추출 cho = cc // (21 * 28) # 초성 값 추출 jung = (cc // 28) % 21 # 중성 값 추출 jong = cc % 28 # 종성 값 추출 print("| %s | %s%s%s |" % (c, HAN_CHO[cho], HAN_JUNG[jung], HAN_JONG[jong] ), end="") print(" 0x%s | %5d |" % ( hex(cc + 44032).upper()[-4:] , cc + 44032) ) print("+----+--------+--------+-------+")
1번 줄은 정규 표현식 모듈을 호출해서 사용하는 부분입니다.
3번 줄에서 10번 줄까지는 한글 낱자를 초성, 중성, 종성으로 나눠서 순서대로 상수 배열을 선언한 부분입니다. 여기서는 편의를 위해 8줄로 나눠서 코딩하였습니다.
※ 한글 전산화에서는 일반적으로 겹낱자(ㄲ, ㄳ, ㅘ 등)은 홑날자(ㄱ, ㄴ, ㅏ 등)와 별개의 글자로 처리합니다. 대한민국(남한)에서는 겹낱자를 그 겹낱자의 앞 낱자를 기준으로 그 홑낱자의 바로 뒤에 배치하고 앞 낱자가 같은 겹낱자끼리는 뒤 낱자를 기준으로 배치(예: ㄱㄲㄳㄴ …)하지만 북한에서는 남한과 다른 방식으로 배치합니다. 유니코드는 남한식 낱자 배열 순서를 따르고 있으므로 이 코드도 마찬가지로 남한식 낱자 배열에 기반하여 작성합니다.
12번 줄에서 텍스트를 입력받은 후, 13번 줄에서는 정규 표현식에 의한 치환을 이용하여 12번 줄에서 입력받은 텍스트를 한글 완성자만 남깁니다.
19번 줄부터 26번 줄까지는 한글 완성자로 이루어진 문자열을 완성자 한 글자씩 처리하는 반복문입니다. 20번 줄에서 한글 완성자의 유니코드 포인터 값을 추출한 후 계산의 편의를 위해 이 값에서 44032를 뺍니다. (이하 P-44032라 칭함)
21번 줄부터 23번 줄까지가 P-44032 값을 토대로 초성, 중성, 종성 값을 찾아내기 위한 부분입니다. 유니코드에서 한글 완성자 부분은 가각갂갃간갅 … 같갚갛개객갞 … 깉깊깋까깍깎 식으로 초성이 같은 588자들이 순서대로 묶여 있고 그 588자의 범위 안에서 중성이 같은 28자들이 순서대로 묶여 있으며 그 28자의 범위 안에서 종성이 순서대로 배열되어 있습니다. 이를 이용해서 23번 줄과 같이 P-44032에서 28을 나눈 나머지를 종성 값으로, 22번 줄과 같이 P-44032에서 28을 나누고 소수점 아래는 버린 뒤 그 값을 21로 나눈 나머지를 종성 값으로, 21번 줄과 같이 P-44032를 588로 나누고 소수점 아래는 버린 값을 초성 값으로 추출합니다.
25번 줄은 그 완성자를 출력하고 분석된 초성, 중성, 종성 낱자를 함께 출력합니다. 또, 26번 줄은 이 낱자의 유니코드 포인터를 16진수와 10진수로 변환한 값을 출력합니다. (※이런 식으로 표기하면 16진수의 자릿수가 달라지기에 정석적인 방법은 아니지만 한글 완성자의 포인터 값 범위는 16진수 값이 항상 4자리이므로 편의상 이렇게 처리하였습니다.)
이 코드의 실행 결과는 다음과 같습니다.
낱자를 분석할 한글 완성자 문자열을 입력하세요: 나랏말싸미 듕귁에 달아 +----+--------+--------+-------+ |글자| 초중종 | Hex | Dec | +----+--------+--------+-------+ | 나 | ㄴㅏ | 0xB098 | 45208 | | 랏 | ㄹㅏㅅ | 0xB78F | 46991 | | 말 | ㅁㅏㄹ | 0xB9D0 | 47568 | | 싸 | ㅆㅏ | 0xC2F8 | 49912 | | 미 | ㅁㅣ | 0xBBF8 | 48120 | | 듕 | ㄷㅠㅇ | 0xB4D5 | 46293 | | 귁 | ㄱㅟㄱ | 0xADC1 | 44481 | | 에 | ㅇㅔ | 0xC5D0 | 50640 | | 달 | ㄷㅏㄹ | 0xB2EC | 45804 | | 아 | ㅇㅏ | 0xC544 | 50500 | +----+--------+--------+-------+