Unicode 정규화기

Unicode에는 네 가지 정규화 형식이 있으며 서로 바꿔 쓸 수 없습니다. NFC와 NFD는 같은 문자를 하나의 코드포인트와 기본 문자+조합 기호 사이에서 재배열합니다. NFKC와 NFKD는 더 나아가 그저 닮아 보이는 문자까지 다시 씁니다 — fi 리거처, 전각 A, 원호 ①, 로마 숫자 Ⅻ. 이 페이지는 같은 텍스트를 네 가지 전부에 통과시키고, 문자마다 무엇이 바뀌었고 왜인지 한 줄씩 인쇄하고, 그래핌을 코드포인트 및 UTF-8 바이트와 대조해 세고, 당신이 고른 형식 아래에서 두 문자열을 비교합니다. 후반부는 아예 나타나지 않는 문자들에 관한 것입니다. 폭 없는 공백, 조인자, 양방향 제어, 이형 선택자, C0와 C1 제어 문자, 사용자 영역 코드포인트, 깨진 서로게이트 절반. 각각 위치와 이름과 함께, 그리고 텍스트 사본에서 벗겨내는 옵션까지.
모든 처리는 브라우저에서 로컬로 이루어집니다 — 데이터는 어떤 서버에도 업로드되지 않습니다.

정규화가 뭔지 확실치 않나요? 쉬운 말로 푼 Unicode 정규화 설명 — 왜 é가 한 문자이거나 두 문자일 수 있고, 그것이 로그인을 깨는 이유.
보고하고 비교할 형식:
이후의 두 상자 비교:
NFC (아직 없음)
NFD (아직 없음)
NFKC (아직 없음)
NFKD (아직 없음)
아직 비교된 것이 없습니다. 두 문자열을 붙여넣고 두 문자열 비교를 누르세요.
첫 번째 문자열, 정규화됨 (아직 없음)
두 번째 문자열, 정규화됨 (아직 없음)
아직 검사된 것이 없습니다. 텍스트를 붙여넣고 보이지 않거나 위험한 문자 검사를 누르세요. 해당 문자를 제거한 텍스트를 원하면 제거를 누르세요.
선택한 클래스가 제거된 텍스트 (아직 없음)
첫 상자에서 Ctrl+Enter가 현재 모드를 실행합니다.
모드를 고르고 그 행동 버튼을 누르세요. 정규화는 텍스트의 네 형식 전부와 문자당 한 줄을 씁니다. 비교는 정규화 후 두 문자열이 같은지 말합니다. 검사는 나타나지 않는 문자들을 나열하고 벗겨낼 수 있습니다. 자체 테스트 버튼은 이 페이지 데이터 파일의 문서화된 사례 전부와 보이지 않는/제어 문자 표의 모든 문자를 다시 돌리고 여기에 개수를 보고합니다.
모든 문자, 한 줄씩:문자의 정체, 네 형식이 그것에 하는 일, 그리고 이유. 음영 행은 적어도 한 형식이 바꾸는 문자입니다. NFD 열은 문자가 분해될 때 무엇으로 분해되는지 보여줍니다.
그것은 문자 몇 개인가?같은 텍스트를 네 가지 방법으로 셉니다: 그래핌 클러스터(읽는 사람이 세는 것), 코드포인트(Unicode가 부여하는 것), UTF-16 유닛(JavaScript가 인덱싱하는 것), UTF-8 바이트(전송되는 것). 정규화는 첫째 열을 바꾸지 않고 둘째와 셋째 열 사이에서 숫자를 옮깁니다.
발견된 것, 나타나는 순서대로:위치는 코드포인트를 세고, 클래스는 문자가 속한 것이며, 설명은 그 문자가 다음에 텍스트를 읽는 대상에게 하는 일을 말합니다.
이 페이지가 의심스러운 것으로 다루는 클래스:표는 검사기 자신에서 인쇄되므로 이 페이지의 말과 버튼의 동작이 어긋날 수 없습니다. 심각도는 그 문자가 무고할 가능성이 아니라 비교에 미치는 영향에 관한 것입니다.
사용자 영역 문자는 나머지와 다른 이유로 의심 목록에 있습니다. 렌더링은 되지만 합의된 의미가 없어 같은 코드포인트가 정의하는 폰트마다 다른 그림이 되기 때문입니다.
이 페이지가 받는 입력 크기와 그 이유:정규화는 문자열 전체의 재조립이고 이 페이지는 그것을 여러 번에 검사와 그래핌 계산까지 더하므로 비용은 입력 길이와 함께 직선으로 자랍니다. 아래 상한이 존재하는 이유는 문자당 한 줄 표가 문서 안에 그려지기 때문이며, 백만 줄짜리 표야말로 실제로 브라우저를 멈춥니다.
Unicode 정규화란?

Unicode는 일부 문자를 쓰는 방법을 하나 이상 줍니다. é는 단일 코드포인트 U+00E9일 수도, 조합 양음 부호 U+0301이 뒤따르는 평범한 e U+0065일 수도 있습니다. 둘은 화면에서 같고 인쇄되어도 같지만 문자열로서는 다릅니다. 길이가 다르고 UTF-8 바이트가 다르며 'é' === 'e\u0301'은 false입니다.

그것은 호기깃거리가 아니라 버그의 한 부류입니다. 어느 형식이 나올지는 키보드 배치, 운영 체제, 입력기, 그리고 텍스트가 워드 프로세서를 거쳤는지에 달려 있습니다. 문자열을 바이트 단위로 비교하는 암호 확인, 데이터베이스 고유 인덱스, 차단 목록, 캐시 키는 두 표기를 두 개의 다른 값으로 다룹니다 — 사용자가 한 기기에서 암호를 설정하고 다른 기기에서 로그인하지 못하거나, 같은 단어가 "이미 사용 중" 이름 목록에 두 번 나타날 수 있습니다.

30초 버전: NFC와 NFD는 같은 텍스트의 두 가지 표기입니다 — NFC는 합성하고(e+부호가 한 문자가 됨), NFD는 분해합니다(한 문자가 e+부호가 됨). 무손실이도록 설계되었으며 비교와 저장에 쓰는 두 형식입니다. NFKC와 NFKD는 앞 두 가지가 하는 일 전부에 더해 호환 문자까지 교체합니다. 리거처 fi가 두 글자가 되고, ½가 1⁄2가 되고, 로마 숫자 ⅲ가 XII가 되고, 전각 A이 평범한 A가 됩니다. 그것이 검색 인덱스나 키워드 필터가 원하는 것이며, 암호에 절대 적용하면 안 되는 것입니다.
왜 네 형식인가

이 분열은 서로 다른 두 목표가 있었기 때문에 존재합니다. 합성과 분해는 정준(canonical) 변경입니다. 결과는 같은 의미이고 첫 두 형식에서는 아무것도 손실되지 않습니다. 리거처, 위첨자, 원호 문자, 전각 형식을 접어 없애는 것은 호환(compatibility) 변경입니다. 매칭의 편의를 위해 이루어지며 Unicode가 다르다고 말하는 두 문자열의 구별을 파괴합니다. 네 형식은 이 두 결정의 모든 조합입니다.

위 표는 이 페이지의 데이터 파일에 있는 사례 목록에서 만들어졌으며, 플랫폼 자체의 String.prototype.normalize와 대조됩니다. 자체 테스트가 표의 모든 행을 눈앞에서 다시 검사합니다. 처음 두 행을 함께 읽어 보세요: 같은 텍스트를 두 가지 방식으로 쓴 것이며, 정규화한 뒤에는 같은 문자열이 됩니다.

풀이 예제

샘플 버튼이 걷는 문자열들로, 답으로 적어 넣은 것이 아니라 페이지가 live로 정규화합니다. 각각은 어떤 형식이 눈에 보이는 일을 하는 경우라서 골랐습니다.

호환 문자: NFKC가 당신에게 청구하는 것

NFKC와 NFKD는 손실이 있으며 그 손실은 의도적입니다. "같은 단어인가"에 답하지 "같은 문자열인가"에 답하지 않습니다. 따르는 세 가지 결과가 있고 셋 다 프로덕션 코드에서 틀리기 쉽습니다:

  • 암호, 토큰, 서명을 호환 형식으로 저장하지 마세요. 서로 다른 입력이 같은 저장값으로 무너져 길이나 문자 검사를 더 약한 것으로 만듭니다. 암호는 NFC로 정규화하고(또는 전혀 하지 말고) 양쪽에 정확히 같은 일을 한 뒤 바이트로 비교하세요.
  • 호환 접기는 한 문자를 여러 개로 만들 수 있습니다. 리거처 fi는 두 글자가 되는 하나의 코드포인트입니다. 정규화 전에 길이를 검증한 필드는 정규화 후 더 길어질 수 있습니다. 정규화 먼저, 그다음 검증, 그다음 저장.
  • NFKC가 보이지 않는 모든 것을 제거하지는 않습니다. 이형 선택자는 NFKC와 NFKD를 survive하고 폭 없는 조인자도 그렇습니다. 그래서 이 페이지에 검사 모드가 있습니다. 정규화는 문자의 모양과 정체에 관한 질문에 답하고 검사기는 무언가 거기 있는지에 관한 질문에 답합니다.
그래핌, 코드포인트, 바이트

정규화는 이 중 둘째를 바꾸고 보통 첫째를 그대로 둡니다. 세 숫자 모두 "텍스트의 길이"이면서 모두 다릅니다. 그래서 20자 제한 폼 필드가 20 코드포인트, 30 UTF-16 유닛, 47바이트인 문자열에 속할 수 있습니다.

그래핌 열의 숫자가 사람이 세는 것입니다. 그것과 코드포인트 수의 간격이 정확히 검사기의 주제입니다. 12개 코드포인트로 이루어진 이름이 화면에서는 12글자로, 3글자와 그 사이의 보이지 않는 기호 9개로, 또는 이모지 하나로 표시될 수 있습니다.

볼 수 없는 문자들

폭 없는 공백은 폭을 차지하지 않고 글리프를 바꾸지 않으며, 실제 코드포인트를 가진 실제 문자입니다. 화면에서 똑같이 보이는 두 식별자가 그것 하나로 다를 수 있고, 그것이 목록의 이름이 옆 이름과 다르게 정렬·검색·인증되는 사칭자가 되는 방식입니다. 양방향 제어 문자도 마찬가지로, 문자열을 쓰인 순서와 다른 순서로 렌더링할 수 있습니다 — 파일 이름을 위장하는 데 쓰인 트릭입니다.

세 번째 모드의 검사기는 그것들을 위치와 함께 전부 나열합니다. 폭 없는 문자와 조인자, 양방향 제어, 이형 선택자, 특수 공백, C0와 C1 제어 문자, 사용자 영역 코드포인트, 그리고 유효한 쌍의 절반이 아닌 서로게이트(문자가 아닙니다). 위쪽의 클래스 표가 각 클래스가 하는 일을 말하고, 제거 버튼은 입력을 건드리지 않고 그 문자들의 사본에서 벗겨냅니다.

이 페이지가 잡으려고 만들어진 실수들
  • 정규화 없이 두 문자열 비교. 'é' === 'e\u0301'은 false입니다. 비교 전에 양쪽을 같은 형식으로 정규화하고, 비교하는 인덱스에서도 같은 형식을 쓰세요.
  • 한쪽만 정규화. 쿼리는 정규화하고 저장값은 정규화하지 않는 조회는 아무것도 못 찾으며 정규화 문제가 아니라 데이터 문제처럼 보입니다.
  • 호환 형식으로 꾸미고 NFC 안전이라 부르기. 암호에 적용한 NFKC는 가능한 암호 공간을 줄이고 구별되어야 할 입력을 합칩니다.
  • 정규화 형식이 사칭을 고친다고 가정. 폭 없는 조인자, 이형 선택자, 동형글자를 제거하지 않습니다 — 키릴 а와 라틴 a는 NFC가 내버려 두는 다른 코드포인트입니다.
  • 문자 수를 믿기. 사용자가 보는 수, 데이터베이스 칼럼이 강제하는 수, 바이트 한도가 강제하는 수는 세 개의 다른 숫자이며 위의 행들이 얼마나 벌어질 수 있는지 보여줍니다.
  • NFC가 받게 될 것이라 가정. 입력기, 파일, 다른 시스템에서 온 텍스트는 그 시스템이 만든 형식 그대로입니다. 이 페이지가 NFC에서 시작하는 것은 웹이 쓰라고 기대하는 형식이기 때문이지 당신의 입력이 그것이어서가 아닙니다.
빠른 답

“왜 이 두 문자열은 똑같이 보이는데 같지 않죠?”

하나는 합성 문자로, 다른 하나는 기본 글자+조합 기호로 쓰였거나, 하나에 아무것도 그리지 않는 문자가 들어 있기 때문입니다. 비교 모드로 전환해 각 상자에 문자열을 하나씩 넣으세요. 페이지가 정규화된 문자열이 처음으로 달라지는 위치와 그 위치에 각각 무엇이 있는지 보고합니다.

“애플리케이션에서는 어느 형식을 써야 하나요?”

사람이 읽고, 표시하고, 저장하고, 검색할 모든 것에는 NFC입니다. W3C가 웹에 권장하는 형식입니다. 뒤의 코드가 기본 글자와 별도의 기호를 원할 때(텍스트 처리와 일부 macOS 파일 시스템에서 흔함)는 NFD가 맞는 답입니다. NFKC와 NFKD는 저장이 아니라 매칭하는 곳에만 쓰세요. 검색 인덱스, 키워드 필터, 중복 감지.

“이미 정규화된 문자열은 거기에 이어 붙여도 여전히 정규화되어 있나요?”

반드시는 아닙니다. 정규화는 연결로 보존되지 않습니다. 두 NFC 문자열을 이어 붙이면 NFC가 다르게 썼을 시퀀스가 나올 수 있습니다. 둘째 문자열 시작의 조합 기호가 첫째 문자열 끝의 문자에 붙을 수 있기 때문입니다. 조립 전에만이 아니라 조립 후에 정규화하세요.

“정규화는 보이지 않는 문자를 제거하나요?”

아니요, 단 하나의 부분적 예외가 있습니다. NFKC와 NFKD는 줄 바꿈 없는 공백을 일반 공백으로 바꾸며 그것은 호환 접기의 보이는 결과입니다. 나머지 전부 — 폭 없는 공백, 조인자, 양방향 제어, 이형 선택자 — 는 네 형식을 거치며 손대지지 않습니다. 세 번째 모드가 그것을 위해 존재합니다.

“왜 문자 수는 안 바뀌는데 바이트 수는 바뀌죠?”

두 형식이 UTF-8에서 다른 바이트 수를 쓰는 서로 다른 코드포인트로 만들어지기 때문입니다. 합성 é는 2바이트, 분해된 쌍은 3바이트입니다. 위의 계수 표가 입력과 각 형식에 대해 네 숫자를 나란히 인쇄하므로 차이가 설명이 아니라 보입니다.

“이 페이지의 결과가 맞는지 어떻게 알죠?”

자체 테스트를 누르세요. 이 페이지 데이터 파일의 모든 사례를 정규화하고, 문서화된 관계에 대해 네 형식을 서로 재검사하고(NFC는 멱등, NFC 문자열의 NFD는 원본의 NFD와 같음 등), 보이지 않는/제어 문자 표의 모든 문자를 검사기에 돌리고, 그래핌 사례를 Intl.Segmenter와 대조해 셉니다.

표준과 출처

네 형식과 그 정의는 Unicode 표준 부속서 15(Unicode Normalization Forms)에서 왔습니다. 분해 예제로 쓰인 코드포인트는 표준이 할당한 것들입니다. 이 페이지는 분해 표를 스스로 구현하지 않고 브라우저 자신의 String.prototype.normalize를 호출합니다. 그것은 플랫폼이 텍스트 입력, 정렬, 비교에 쓰는 것과 같은 구현이므로 여기서 보고되는 것이 시스템의 나머지가 같은 문자열에 하는 일입니다. 그래핌 클러스터는 브라우저에 있으면 Intl.Segmenter에서, 없으면 문서화된 근사에서 옵니다.

이 페이지의 텍스트는 이 사이트를 위해 작성되었습니다. 이 페이지의 모든 풀이 예제는 페이지 자신의 코드로 생성된 뒤 데이터 파일의 기록된 사례 목록과 대조되었고, 그 목록은 같은 문자들에 대해 Unicode NormalizationTest 데이터와 대조되었습니다. 보이지 않는/위험 문자 표는 완전한 Unicode 보안 프로파일(UTS #39)이 아니라 사람이 읽을 수 있는 경고를 위해 쓴 선별 부분집합이며, 페이지는 갖추지 못한 완전성을 암시하는 대신 그렇게 말합니다.