RAG를 진행하며, 문자의 통일 및 비교에 대한 내용을 많이 접하였다.
그 중에서 유니코드 정규화라는 개념이 중요시되어, 이를 간략하게 정리하고자 한다.
유니코드(Unicode)는 전 세계의 모든 문자와 기호를 컴퓨터에서 일관되게 표현하기 위해 만든 국제 표준 문자 인코딩 체계이다.
쉽게 말해, “문자를 숫자로 약속하는 규칙”이다.
⭐ 눈으로 보면 똑같이 보이지만, 내부적으로는 서로 다른 코드 포인트 조합으로 표현될 수 있는 문자를 하나의 표준 형태로 맞추는 과정
EUC-KR
, CP949
Shift-JIS
ISO-8859-1
, ASCII
유니코드에서는 같은 글자라도 여러 방식으로 표현이 가능하다.
✅ 예를 들어:
U+00E9
(é)U+0065
(e) + U+0301
(´)겉보기에는 똑같이 "é"지만, 메모리 속 이진 값은 달라서
문자 비교("é" == "é"
)나 문자열 검색에서 문제가 생길 수 있다.
유니코드는 이런 문제를 해결하기 위해 “하나의 전 세계 공통 문자 코드 체계”를 정의했다.
U+0041
U+AC00
U+1F600
UTF-8
은 웹에서 가장 많이 쓰이는 방식으로, 영어는 1바이트, 한글은 3바이트로 표현된다.U+0000 ~ U+FFFF
(한글, 한자, 알파벳 등 대부분 포함)안
→ EC 95 88
녕
→ EB 85 95
👉 정리하면, 유니코드 = 문자에 부여한 국제 공용 번호 체계,
그리고 UTF-8/16 같은 방식 = 그 번호를 실제 컴퓨터에서 저장·전송하는 방법.
유니코드 표준에서는 크게 4가지 정규화 형식을 정의한다:
방식 | 설명 | 예시 |
---|---|---|
NFC (Normalization Form C) | 조합할 수 있는 문자는 하나로 합침(합성) | e + ´ → é |
NFD (Normalization Form D) | 모든 문자를 가능한 한 분리(분해) | é → e + ´ |
NFKC (Compatibility Composition) | 모양만 다른 호환 문자를 표준 문자로 합성 | ① → 1 |
NFKD (Compatibility Decomposition) | 모양만 다른 문자를 분해 후 표준화 | ① → 1 |
import unicodedata
s1 = "é" # 단일 코드포인트 U+00E9
s2 = "e\u0301" # 조합형: U+0065 + U+0301
print(s1 == s2) # False (겉보기는 같지만 내부 코드 다름)
# 정규화 후 비교
print(unicodedata.normalize("NFC", s1) == unicodedata.normalize("NFC", s2)) # True
RAG를 구현할때, 아래의 함수를 빈번하게 활용했다.
def normalize_category_text(text: str) -> str:
"""카테고리 텍스트 정규화 함수
- ⭐ 추가: 같은 한글도 자음/모음 결합 방식이 상이할 수 있음 => 정규화 필요
Args:
text: 정규화할 카테고리 텍스트
Returns:
정규화된 카테고리 텍스트
"""
if not text:
return text
# 1. 유니코드 정규화 (NFC - 완성형으로 통일)
normalized = unicodedata.normalize('NFC', text)
# 2. 공백을 언더바로 통일
normalized = normalized.replace(' ', '_')
# 3. 연속된 언더바를 하나로 통합
normalized = re.sub(r'_+', '_', normalized)
# 4. 앞뒤 공백/언더바 제거
normalized = normalized.strip('_ ')
return normalized
✅ 정리하면:
정규화 = 서로 다른 유니코드 표현을 같은 규칙(NFC, NFD 등)에 맞춰 ‘동일한 코드열’로 통일하는 과정이다.