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

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

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



답변

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

정식 정규화

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

사용시기

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

정식 정규화는 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를 선택하십시오.


답변

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

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

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

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


답변

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

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

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

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


답변

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

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

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

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


답변

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

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

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

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

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


답변

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

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

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


답변

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

유니 코드의 표준 동등성을 참조하십시오 . 비교 알고리즘이 단순하거나 빠르면 유니 코드 동등성 이 수행되지 않습니다. 이 문제는 예를 들어 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 엔터티 참조)의 정규화를 테스트 하려면 이 테스트 / 정규화 온라인 변환기를 사용할 수 있습니다 .