db에 있는 텍스트를 파일로 저장하는 기능을 개발했다. 그런데 파일의 텍스트가 자모음 분리가 되는 것 아닌가.
이유는 유니코드 정규화와 관련된 문제였다.
해결방법부터 보자면 아래와 같다.
import unicodedata
text = '...'
nfc_text = unicodedata.normalize('NFC', text)
이렇게 NFC 정규화를 해준 후 저장하면 문제가 없다.
그럼 유니코드 정규화란 뭔지 보겠다.
우선 유니코드는 세상의 모든 문자에 대해 숫자를 대응시키는 규격이라고 보면 된다. python에서는 ord함수로 간단히 유니코드를 확인할 수 있다.
text = '가'
unicode = ord(text) #44032
보시다시피 '가' 라는 글자에 숫자가 배정돼있다. 그럼 'ㄱ' 과 'ㅏ'는 어떻게 표현될까. 물론 각각의 자모음에도 서로 다른 유니코드가 배정된다.
ord('ㄱ') #12593
ord('ㅏ') #12623
그럼 'ㄱ' 과 'ㅏ' 를 입력하면 컴퓨터에서는 어떻게 처리할까. 이것에 대한 해답이 유니코드 정규화다. NFC정규화는 'ㄱ' 과 'ㅏ'를 합친 '가' 라는 완성형 문자에 대한 유니코드를 할당한다. 반면에 NFD정규화는 'ㄱ' 따로 'ㅏ' 따로 저장하게 된다. 참고로 NFD에서 'ㄱ', 'ㅏ' 는 각각 NFC에서와 다른 유니코드를 갖는다. 완성형이 아닌 조합형이기 때문이다.
좀 더 자세히 설명하면 위의 예시에서 'ㄱ'은 받침이 아닌 모음과 결합되는 'ㄱ'이고 'ㅏ'는 단독으로 쓰이지 않은 자음과 결합된 'ㅏ' 이다. 코드로 직접 확인해보자.
import unicodedata as ud
def print_ord(text):
for c in text:
print(ord(c), end=' ')
print()
def compare(text):
n_list = ['NFC', 'NFD']
for n_type in n_list:
n_text = ud.normalize(n_type, text)
print(n_type, end=': ')
print_ord(n_text)
text = '가'
compare(text)
# 실행결과
# NFC: 44032
# NFD: 4352 4449
위의 함수를 그대로 사용하여 '응' 을 확인해보자 NFD 결과를 보면 위의 자음 'ㅇ' 과 받침 자음 'ㅇ' 의 유니코드가 다름을 확인할 수 있다.
...
compare('응')
# 실행결과
# NFC: 51025
# NFD: 4363 4467 4540
'trouble-shooting' 카테고리의 다른 글
alpine linux에 mysql 설치하며 해결한 문제 기록 (3) | 2024.09.05 |
---|---|
TypeError: can't subtract offset-naive and offset-aware datetimes (0) | 2022.11.22 |
[python] generator는 일회용? (map, filter와 같은 함수를 쓸 때 생기는 문제) (0) | 2022.11.11 |
TypeError: Object of type datetime is not JSON serializable (0) | 2022.11.11 |
json.dumps 한글 (0) | 2022.11.09 |