정규화 된 UTF-8이란 무엇입니까?


129

ICU 프로젝트는 (또한 지금 갖고있는 PHP 라이브러리를 ) 검색 할 때 쉽게 값을 비교할 수 있도록 도움 정규화 UTF-8 문자열에 필요한 클래스가 포함되어 있습니다.

그러나 이것이 응용 프로그램에 대한 의미 를 알아 내려고 노력 중 입니다. 예를 들어 어떤 경우에 "호환성 동등성"대신 "정식 동등성"을 원하십니까?


230
누가 ̸͢k̵͟n̴͘ǫw̸̛s͘ w͘͢ḩ̵a҉̡͢t 공포 거짓말 어두운 마음의 유니 코드 ͞
ObscureRobot

@ObscureRobot 나는 그 추가 심볼들이 상태를 가질 수 있는지 아닌지를 알고 싶다
eonil

1
@Eonil-유니 코드의 맥락에서 상태가 무엇을 의미하는지 잘 모르겠습니다.
ObscureRobot

@ObscureRobot 예를 들어 다음과 같은 일부 코드 (begin curved line) (char1) (char2) … (charN) (end curved line)는 다음과 같습니다 (curved line marker prefix) (char1) (curved line marker prefix) (char2) (curved line marker prefix) (char2). 다시 말해, 렌더링 할 수있는 최소 단위는?
eonil

2
그것은 좋은 질문처럼 들립니다.
ObscureRobot

답변:


181

유니 코드 정규화에 대해 알고 싶지 않은 모든 것

정식 정규화

유니 코드에는 일부 문자 (가장 두드러진 강조 문자)를 인코딩하는 여러 가지 방법이 있습니다. 표준 정규화는 코드 포인트를 표준 인코딩 형식으로 변경합니다. 결과 코드 포인트는 글꼴 또는 렌더링 엔진의 버그를 제외하고 원래 코드 포인트와 동일하게 나타납니다.

사용시기

결과가 동일하게 표시되므로 입력과 비트가 동일하지 않은 결과를 허용하지 않는 한 문자열을 저장하거나 표시하기 전에 표준 정규화를 문자열에 적용하는 것이 항상 안전합니다.

정식 정규화는 NFD와 NFC의 두 가지 형태로 제공됩니다. 이 두 형식은 손실없이 두 형식간에 변환 할 수 있다는 점에서 동일합니다. NFC에서 두 문자열을 비교하면 항상 NFD에서 비교하는 것과 동일한 결과를 얻을 수 있습니다.

NFD

NFD는 문자가 완전히 확장되었습니다. 이것은 계산하는 가장 빠른 정규화 형식이지만 결과적으로 더 많은 코드 포인트가 생성됩니다 (예 : 더 많은 공간 사용).

아직 정규화되지 않은 두 문자열을 비교하려는 경우 호환성 정규화가 필요하다는 것을 알지 않는 한 선호되는 정규화 양식입니다.

NFC

NFC는 NFD 알고리즘을 실행 한 후 가능하면 코드 포인트를 재결합합니다. 시간이 조금 더 걸리지 만 줄이 짧아집니다.

호환성 정규화

유니 코드에는 실제로 속하지는 않지만 레거시 문자 집합에 사용 된 많은 문자가 포함됩니다. 유니 코드는 이러한 문자 세트의 텍스트를 유니 코드로 처리 한 다음 손실없이 다시 변환 할 수 있도록하기 위해 추가했습니다.

호환성 정규화는 이들을 대응하는 "실제"문자 시퀀스로 변환하고 표준 정규화도 수행합니다. 호환성 정규화 결과가 원본과 동일하게 나타나지 않을 수 있습니다.

서식 정보가 포함 된 문자는 그렇지 않은 문자로 바뀝니다. 예를 들어 문자 는로 변환됩니다 9. 다른 것들은 서식 차이를 포함하지 않습니다. 예를 들어 로마 숫자 문자 는 일반 문자로 변환됩니다 IX.

분명히이 변환이 수행되면 더 이상 손실없이 원래 문자 세트로 다시 변환 할 수 없습니다.

사용시기

유니 코드 컨소시엄은 ToUpperCase변환 과 같은 호환성 정규화에 대한 생각을 제안 합니다. 그것은 어떤 상황에서는 유용 할 수 있지만, 단지 윌리-니 일로 적용해서는 안됩니다.

당신이 아마 9일치 하는 검색을 원할 것이기 때문에 훌륭한 사용 사례는 검색 엔진이 될 것입니다 .

호환성 정규화를 사용자에게 적용한 결과를 표시하지 않아야 할 수도 있습니다.

NFKC / NFKD

호환성 정규화 양식은 NFKD와 NFKC의 두 가지 형태로 제공됩니다. 그들은 NFD와 C와 같은 관계를 가지고 있습니다.

NFKC의 모든 문자열은 본질적으로 NFC에도 있으며 NFKD 및 NFD의 경우에도 동일합니다. 따라서 NFKD(x)=NFD(NFKC(x)), NFKC(x)=NFC(NFKD(x))

결론

의심스러운 경우 표준 정규화를 사용하십시오. 적용 가능한 공간 / 속도 상충 관계 또는 상호 운용중인 항목에 필요한 사항에 따라 NFC 또는 NFD를 선택하십시오.


42
약어의 의미를 기억하기위한 빠른 참조 : NF = 정규화 된 형식 D = 분해 (압축 해제) , C = 작성 (압축) K = 호환성 ( "C"이후).
Mike Spross

12
입력시 모든 문자열을 맨 처음 NFD로하고 NFC 모든 문자열을 마지막으로 출력하려고합니다. 이것은 잘 알려져 있습니다.
tchrist

3
@tchrist : 변경 사항이 없을 때 출력이 입력과 동일한 바이트 단위로 출력되는 드문 경우를 제외하고는 일반적으로 좋은 조언입니다. 메모리의 NFC 또는 디스크의 NFD를 원하는 다른 경우가 있지만 규칙이 아닌 실행입니다.
Kevin Cathcart

@Kevin : 예. NFD 입력과 NFC 출력은 싱글 톤을 파괴합니다. 나는 누군가가 그에 관심이 있는지 확실하지 않지만 가능할 것입니다.
tchrist

2
당신은 생각할 수도 있지만, 부록에서 : "유니 코드 문자열을 주어진 유니 코드 정규화 형식으로 변환하려면 첫 번째 단계는 문자열을 완전히 분해하는 것"입니다. 따라서 NFC를 실행하는 경우에도 Q-Caron은 먼저 Q + Caron이되어 안정성 규칙에 따라 새 컴포지션 매핑을 추가 할 수 없으므로 재구성 할 수 없었습니다. NFC는 효과적으로로 정의됩니다 NFC(x)=Recompose(NFD(x)).
케빈 카스 카트

40

예를 들어 악센트가있는 문자와 같은 일부 문자 é는 단일 코드 포인트 U+00E9또는 일반 문자 다음에 결합 악센트 표시가 있는 두 가지 방식으로 표현 될 수 있습니다 U+0065 U+0301. 보통의 정규화는 이들 중 하나를 항상 나타 내기 위해 선택할 것입니다 (NFC의 단일 코드 포인트, NFD의 결합 형태).

기본 시퀀스의 여러 시퀀스로 표시되고 마크를 조합 할 수있는 문자 (예 : "s, 아래 도트, 위 도트"대 vs. 도트 위의 도트 아래 또는 이미 도트 중 하나가있는 기본 문자 사용)의 경우 NFD는 또한 다음 중 하나를 선택하십시오 (아래에서 먼저 진행됨)

호환성 분해에는 "실제로는 안되는"문자이지만 레거시 인코딩에 사용 된 여러 문자가 포함됩니다. 일반적인 정규화는 이들을 통합하지 않습니다 (왕복 무결성을 유지하기 위해-레거시 인코딩 (소수의 베트남어 인코딩 제외)이 둘 다 사용되지 않기 때문에 결합 형식에는 문제가되지 않습니다). 그러나 호환성 정규화는 가능합니다. 일부 동아시아 인코딩 (또는 반자 / 전각 가타카나 및 알파벳) 또는 MacRoman의 "fi"합자에 나타나는 "kg"킬로그램 기호를 생각하십시오.

자세한 내용은 http://unicode.org/reports/tr15/ 를 참조하십시오.


1
이것은 실제로 정답입니다. 일부 레거시 문자 집합에서 시작된 텍스트에 정식 정규화 만 사용하면 결과를 손실없이 해당 문자 집합으로 다시 변환 할 수 있습니다. 호환성 분해를 사용하면 호환성 문자없이 종료되지만 더 이상 손실없이 원래 문자 세트로 다시 변환 할 수 없습니다.
Kevin Cathcart

13

데이터베이스가 아닌 유니 코드의 일반 형식은 분음 부호가있는 문자를 주로 처리합니다. 유니 코드는 U + 00C0, "Latin Capital A with Grave"와 같이 "내장"분음 부호가있는 문자를 제공합니다. "Latin Capital A"(U + 0041)에서 "Combining Grave Accent"(U + 0300)로 동일한 문자를 만들 수 있습니다. 이는 두 시퀀스가 ​​동일한 결과 문자를 바이트 단위로 생성하더라도 비교는 그것들이 완전히 다른 것으로 보여줄 것입니다.

정규화는 그 문제를 해결하려는 시도입니다. 정규화하면 모든 문자가 동일한 방식으로 인코딩됩니다 (모두 필요한 경우 별도의 결합 분음 부호를 사용하거나 가능한 경우 단일 코드 포인트를 사용함). 비교의 관점에서, 실제로 선택하는 것이 중요하지 않습니다. 정규화 된 문자열은 다른 정규화 된 문자열과 제대로 비교됩니다.

이 경우 "호환성"은 하나의 코드 포인트가 하나의 문자와 같다고 가정하는 코드와의 호환성을 의미합니다. 그런 코드가 있다면 호환성 일반 형식을 사용하고 싶을 것입니다. 필자가 직접 언급 한 것을 본 적이 없지만 일반 형식의 이름은 유니 코드 컨소시엄이 별개의 결합 분음 부호를 사용하는 것이 바람직하다고 간주 함을 의미합니다. 이를 위해서는 문자열에서 실제 문자를 계산하는 데 더 많은 지능이 필요하지만 (현명하게 문자열을 깨는 것과 같은 것) 더 융통성이 있습니다.

ICU를 최대한 활용하는 경우 표준 정규 형식을 사용하고 싶을 수 있습니다. 예를 들어 코드 포인트가 문자와 같다고 가정하는 코드를 직접 작성하려는 경우 가능한 한 자주 적용되는 호환성 일반 형식을 원할 것입니다.


이것이 Grapheme 함수가 들어온 부분 입니다. 문자는 ASCII보다 바이트 수가 많을뿐만 아니라 여러 시퀀스가 ​​단일 문자가 될 수 있습니까? ( MB 문자열 기능 과 반대 )
Xeoncross

4
아니요, '한 코드 포인트는 한 문자입니다'는 대략 NFC에 해당합니다 (결합 마크가있는 것은 NFD이며 둘 중 어느 것도 "호환성"이 아님)-호환성 정규화 NFKC / NFKD는 다른 문제입니다. 그리스어 mu 및 'micro'에 대해 별도의 문자가있는 레거시 인코딩의 호환성 (또는 부족) ( "호환성"버전이 라틴어 1 블록에있는 것이기 때문에 재미있는
것임

@ Random832 : 죄송합니다. 작년이나 이틀 동안 일하지 않았을 때 기억에서 벗어나는 것보다 더 잘 알아야합니다.
Jerry Coffin

@ Random832 사실이 아닙니다. 당신의 "거의"가 너무 있습니다. ō̲̃와 ȭ̲의 두 그래프를 고려하십시오. 각각을 작성하는 방법에는 여러 가지가 있으며, 정확히 하나는 NFC와 하나의 NFD이지만 다른 것도 존재합니다. 단 하나의 코드 포인트 만있는 것은 아닙니다. 첫 번째는 NFD "o\x{332}\x{303}\x{304}"이고 NFC는 "\x{22D}\x{332}"입니다. 두 번째로 NFD는 "o\x{332}\x{304}\x{303}"이고 NFC는 "\x{14D}\x{332}\x{303}"입니다. 그러나, 이것과 정식으로 동등한 많은 비정규적인 가능성이 존재합니다. 정규화는 정규적으로 동등한 grapheme의 이진 비교를 허용합니다.
tchrist

5

두 개의 유니 코드 문자열이 정식으로 동등한 경우 문자열은 실제로 동일하며 다른 유니 코드 시퀀스 만 사용합니다. 예를 들어 Ä는 문자 Ä 또는 A와 ◌̈의 조합을 사용하여 나타낼 수 있습니다.

문자열이 호환성 만 같으면 문자열이 반드시 같을 필요는 없지만 일부 상황에서는 동일 할 수 있습니다. 예를 들어 ff는 ff와 동일하게 간주 될 수 있습니다.

따라서 문자열을 비교하는 경우 호환성 동등성이 실제 동등하지 않기 때문에 표준 동등성을 사용해야합니다.

그러나 문자열 집합을 정렬하려면 호환성 동등성을 거의 동일하게 사용하는 것이 좋습니다.


5

이것은 실제로 매우 간단합니다. UTF-8은 실제로 동일한 "문자"의 여러 가지 다른 표현을 가지고 있습니다. (바이트 단위이므로 따옴표로 문자를 사용하지만 실제로는 동일합니다.) 링크 된 문서에 예제가 있습니다.

문자 "Ç"은 바이트 시퀀스 0xc387로 표시 될 수 있습니다. 그러나 C바이트 시퀀스 0xcca7 뒤에 (0x43) 이 표시 될 수도 있습니다 . 따라서 0xc387과 0x43cca7은 같은 문자라고 말할 수 있습니다. 작동하는 이유는 0xcca7이 결합 표시이기 때문입니다. 즉, 문자를 C여기 (a ) 보다 먼저 가져 와서 수정합니다.

이제 표준 동등성과 호환성 동등성의 차이에 대해서는 일반적으로 문자를 살펴 봐야합니다.

값을 통해 의미를 전달하는 문자와 다른 문자를 사용하여 변경하는 문자의 두 가지 유형이 있습니다. 9는 의미있는 성격입니다. 위첨자 ⁹는 그 의미를 취하여 그것을 표현으로 바꾼다. 따라서 표준 적으로는 다른 의미를 갖지만 여전히 기본 특성을 나타냅니다.

정식 동등성은 바이트 시퀀스가 ​​동일한 문자를 동일한 의미로 렌더링하는 곳입니다. 호환성 동등성은 바이트 시퀀스가 ​​동일한 기본 의미로 다른 문자를 렌더링하는 경우입니다 (변경 될 수 있음에도 불구하고). 9와 ⁹는 모두 "9"를 의미하기 때문에 호환성이 동일하지만 동일한 표현을 갖지 않기 때문에 정식으로 동일하지 않습니다.


@tchrist : 답을 다시 읽으십시오. 동일한 코드 포인트를 나타내는 다른 방법에 대해서는 언급하지 않았습니다. 나는 결합 된 문자 와 여러 문자를 통해 동일한 인쇄 문자 를 나타내는 여러 가지 방법이 있다고 말했습니다 . UTF-8과 유니 코드 모두에 적용됩니다. 따라서 귀하의 공감과 의견은 내가 말한 것에 전혀 적용되지 않습니다. 사실, 나는 기본적으로 상단 포스터가 여기 (안뿐만 아니라,이기는하지만) 만든 것과 같은 지점을 만들고 있었다 ...
ircmaxell

4

표준 동등성 또는 호환성 동등성이보다 관련성이 있는지 여부는 응용 프로그램에 따라 다릅니다. 문자열 비교에 대한 ASCII 사고 방식은 대략 표준 동등성에 대응하지만 유니 코드는 많은 언어를 나타냅니다. 유니 코드가 모든 언어를 서유럽 ASCII처럼 취급 할 수있는 방식으로 인코딩한다고 가정하는 것이 안전하지 않다고 생각합니다.

그림 1과 2 는 두 가지 유형의 동등성에 대한 좋은 예를 제공합니다. 호환성 동등성에서 하위 스크립트와 수퍼 스크립트 형식의 동일한 숫자가 동일한 것으로 보입니다. 그러나 나는 필기체 아랍어 형식이나 회전 된 문자와 같은 문제를 해결할지 확신하지 못합니다.

유니 코드 텍스트 처리의 어려운 점은 응용 프로그램의 텍스트 처리 요구 사항에 대해 깊이 생각한 다음 사용 가능한 도구를 사용하여 처리 할 수 ​​있어야한다는 것입니다. 그것은 당신의 질문을 직접적으로 다루지는 않지만, 더 자세한 대답은 당신이 지원할 각 언어에 대한 언어 전문가를 필요로합니다.


1

문자열 비교 문제 : 대부분의 응용 프로그램의 목적에 해당하는 내용의 두 문자열은 다른 문자 시퀀스를 포함 할 수 있습니다.

유니 코드의 표준 동등성을 참조하십시오 . 비교 알고리즘이 단순하거나 빠르면 유니 코드 동등성 이 수행되지 않습니다. 이 문제는 예를 들어 XML 표준 비교에서 발생합니다. http://www.w3.org/TR/xml-c14n

이 문제를 피하려면 ... 어떤 표준을 사용해야합니까? "확장 UTF8"또는 "컴팩트 UTF8"?
"ç"또는 "c + ◌̧"를 사용 하시겠습니까?

W3C 및 기타 (예 : 파일 이름 )는 "표준 형식으로 구성"( "가장 작은"짧은 문자열의 C를 고려)을 사용하도록 제안합니다. 따라서,

표준은 C입니다 ! 의심 스러운 NFC 사용

상호 운용성과 "컨벤션 오버 컨벤션"선택을 위해서는 NFC를 사용하여 외부 스트링을 "정상화" 하는 것이 좋습니다 . 예를 들어, 표준 XML을 저장하려면 "FORM_C"에 저장하십시오. 웹 워킹 그룹 의 W3C CSV는 NFC를 추천한다 (섹션 7.2).

PS : de "FORM_C"는 대부분의 라이브러리에서 기본 형식 입니다. 전의. PHP의 normalizer.isnormalized ()에서 .


THER 용어 " 를 compostion의 형태는"( FORM_C) (a NFC 변환의 결과) "문자열은 C-정준 형태"라고하고, 참조 ... 변형 알고리즘을 사용하는 것을 말하고, 모두 사용 에 http : //www.macchiato.com/unicode/nfc-faq

(...) 각각의 다음 시퀀스 (처음 두 문자는 단일 문자 시퀀스 임)는 동일한 문자를 나타냅니다.

  1. U + 00C5 (Å) 링 위의 라틴 대문자 A
  2. U + 212B (Å) 각도 표시
  3. U + 0041 (A) 라틴 대문자 A + U + 030A (̊) 결합 링 위

이러한 시퀀스를 정식 등가라고합니다. 는 C를위한 정규화 양식 C 위해 - 이러한 형태의 제는 NFC라고 를 compostion . (...) 문자열 S를 NFC 형식으로 변환하는 함수는로 축약 될 수 있으며 toNFC(S)S가 NFC에 있는지 테스트하는 기능은로 축약됩니다 isNFC(S).


참고 : 작은 문자열 (순수한 UTF-8 또는 XML 엔터티 참조)의 정규화를 테스트 하려면 이 테스트 / 정규화 온라인 변환기를 사용할 수 있습니다 .


혼란 스러워요. 이 온라인 테스터 페이지로 이동하여 "TÖST MÉ pleasé"로 들어갑니다. 주어진 정규화 중 4 가지를 모두 시도하십시오. 문자를 표시하는 데 사용되는 코드가 변경되는 것을 제외하고는 내 텍스트를 변경하지 않습니다. "정규화"는 "모든 분음 부호 및 유사 항목 제거"를 의미한다고 잘못 생각하고 있으며 실제로는 아래의 utf 코딩을 변경하는 것입니까?
userfuser

안녕하세요 @userfuser 아마도 응용 프로그램에 대한 입장이 필요할 것입니다 : 텍스트 를 비교 하거나 표준화하는 것입니까? 내 게시물은 응용 프로그램을 "표준화"하는 것입니다. 추신 : 모든 세계가 표준을 사용하면 비교 문제가 사라집니다.
피터 크라우스
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.