제대로 비교하기 위해 유니코드 정규화하기

매일 공부(ML)·2022년 11월 23일
0

Fluent Python

목록 보기
23/130

텍스트와 바이트

제대로 비교하기 위해서 유니코드 정규화하기

유니코드에는 결합 문자가 있어서 문자열 비교가 간단하지 않고 앞 문자에 연결되는 발음 구별 기호는 인쇄 시 앞 문자와 하나로 결합되어 출력된다.

s1 = 'cafe'
s2 = 'cafe\u0301'
s1,s2
len(s1),len(s2)
s1 == s2

위에서 보는 것처럼 파이썬은 서로 다른 두 개의 코드 포인트 시퀀스를 보고, 이 둘은 서로 동일하지 않다고 판단한다.


해결방법은 unicodedata.normalize() 함수가 제공하는 유니코드 정규화를 이용해야 하고, 첫번째 인수는 NFC, NFD, NFKC, NFKD 중 하나여야 한다.

정규화 방식 NFC(Normalization Form C),NFD

코드 포인트를 조합해서 가장 짧은 동일 문자열을 생성하고, NFD는 조합된 문자를 기본 문자와 별도의 문자로 분리한다.

키보드에서 입력되는 기본적인 형태이고, 안전을 보장하기 위해서 파일에 저장하기 전에 코드로 문자열을 청소하는 것이 좋습니다.

from unicodedata import normalize
s1 = 'cafe'
s2 = 'cafe\u0301'
len(s1), len(s2)
len(normalize('NFC',s1)), len(normalize('NFC', s2))
len(normalize('NFD',s1)), len(normalize('NFD', s2))

normalize('NFC',s1) == normalize('NFC',s2)
normalize('NFD',s1) == normalize('NFD',s2)

정규화 방식: NFKC, NFKD

K는 호환성을 나타내고, 정규화의 강력한 형태이므로 하나의 규범적인 코드를 가지는 것이 유니코드의 목표 중 하나였지만 기존 표준과의 호환성을 위해서 두 번 이상 나타나는 문자도 있다.

NFKC와 NFKD 방식에서 각 호환성 문자는 포매팅 손실이 발생해도 선호하는 형태의 하나 이상의 문자로 구성된 호환성 분할로 치환이 되고, 이상적으로 포매팅은 외부 표시의 책임이지 유니코드의 책임이 아니다.

물론, Normalize()함수는 포맷에 대해서 전혀 모르기에 NFKC or NFKD는 정보를 왜곡할 순 있지만 검색 및 색인 생성을 위한 편리한 중간 형태를 생성할 수 있다.

from unicodedata import normalize, name
half ='1/2'
normalize('NFKC', half)
four_squared = '42'
normalize('NFKC', four_squared)

케이스 폴딩

모든 텍스트를 소문자로 변환하는 연산으로 약간의 변환을 동반하고, latin1문자만 담고 있는 문자열의 s의 경우 s.casefold()와 s.lower()를 실행한 결과가 동일하다.

micro ='M'
name(micro)
micro_cf = micro.casefold()
name(micro_cf)

정규화된 텍스트 매칭을 위한 유틸리티 함수

NFC는 대부분의 애플리케이션에서 사용할 수 있는 최고의 정규화된 형태이고, str, casefold()는 대소문자 구분없이 문자를 비교할 때 가장 좋은 방법입니다.

다양한 언어로 구성된 텍스트를 사용하는 경우, nfc_equal()과 fold_equal() 메서드를 도구상자에 추가하는 것이 좋다.

from unicodedata import normalize

def nfc_equal(str1, str2):
	return normalize('NFC', str1) == normalize('NFC', str2)
    
def fold_equal(str1, str2):
	return (normalize('NFC', str1).casefold() == normalize('NFC', str2).casefold())
profile
성장을 도울 아카이빙 블로그

0개의 댓글