Что такое нормализованный UTF-8?

на проект ICU (который также теперь имеет библиотека PHP) содержит классы, необходимые для нормализации строк UTF-8, чтобы упростить сравнение значений при поиске.

тем не менее, я пытаюсь понять что это значит для приложений. Например, в каких случаях я хочу "каноническую эквивалентность" вместо "эквивалентности совместимости" или наоборот?

7 ответов


все, что вы никогда не хотели знать о нормализации Unicode

Каноническая Нормализация

Unicode включает в себя несколько способов кодирования некоторых символов, особенно акцентированных символов. Каноническая нормализация изменяет кодовые точки в каноническую форму кодирования. Результирующие кодовые точки должны быть идентичны исходным, за исключением ошибок в шрифтах или движке рендеринга.

При Использовании

потому что результаты кажутся идентичными, всегда безопасно применять каноническую нормализацию к строке перед ее сохранением или отображением, если вы можете терпеть результат, не являющийся битом для бита, идентичного входу.

каноническая нормализация поставляется в 2 формах: NFD и NFC. Они эквивалентны в том смысле, что между этими двумя формами можно конвертировать без потерь. Сравнение двух строк под NFC всегда даст тот же результат, что и сравнение их под NFD.

NFD

NFD имеет символы полностью развернуты. Это более быстрая форма нормализации для вычисления, но результаты в большем количестве кодовых точек (т. е. использует больше пространства).

если вы просто хотите сравнить две строки, которые еще не нормализованы, это предпочтительная форма нормализации, если вы не знаете, что вам нужна нормализация совместимости.

NFC

NFC рекомбинирует кодовые точки, когда это возможно после запуска NFD алгоритм. Это занимает немного больше времени, но приводит к более коротким строкам.

Нормализация Совместимости

Unicode также включает много символов, которые действительно не принадлежат, но использовались в устаревших наборах символов. Unicode добавил их, чтобы текст в этих наборах символов обрабатывался как Unicode, а затем преобразовывался обратно без потерь.

нормализация совместимости преобразует их в соответствующую последовательность "реальных" символов, а также выполняет каноническую нормализацию. Результаты нормализации совместимости могут не совпадать с оригиналами.

символы, содержащие информацию о форматировании, заменяются символами, которые этого не делают. Например, символ преобразуется к виду 9. Другие не включают различия в форматировании. Например, Римская цифра преобразуется в обычные буквы IX.

очевидно, как только это преобразование было это уже невозможно без потерь преобразовать обратно в исходный набор символов.

при использовании

консорциум Unicode предлагает думать о нормализации совместимости, как ToUpperCase трансформировать. Это то, что может быть полезно в некоторых обстоятельствах, но вы не должны просто применять его волей-неволей.

отличным вариантом использования будет поисковая система, так как вы, вероятно, захотите найти 9 в матче .

одна вещь, которую вы, вероятно, не должны делать, - это отображать результат применения нормализации совместимости к пользователю.

NFKC / NFKD

форма нормализации совместимости поставляется в двух формах NFKD и NFKC. Они имеют те же отношения, что и между NFD и C.

любая строка в NFKC по своей сути также находится в NFC, и то же самое для NFKD и NFD. Таким образом NFKD(x)=NFD(NFKC(x)) и NFKC(x)=NFC(NFKD(x)), etc.

вывод

если есть сомнения, идите с канонической нормализацией. Выберите NFC или NFD на основе применимого компромисса пространства/скорости или на основе того, что требуется от того, с чем вы взаимодействуете.


некоторые символы, например буквы с ударением (например, é) может быть представлен двумя способами-одной кодовой точкой U+00E9 или простая буква, за которой следует комбинированный знак ударения U+0065 U+0301. Обычная нормализация выберет один из них, чтобы всегда представлять его (одна кодовая точка для NFC, комбинированная форма для NFD).

для символов, которые могут быть представлены несколькими последовательностями базовых символов и сочетанием знаков (скажем, "s, точка ниже, точка выше" vs поставив точку выше, затем точку ниже или используя базовый символ, который уже имеет одну из точек), NFD также выберет один из них (ниже идет первым, как это происходит)

декомпозиции совместимости включают ряд символов, которые" не должны быть " символами, но потому, что они использовались в устаревших кодировках. Обычная нормализация не объединит их (для сохранения целостности туда и обратно - это не проблема для комбинированных форм, потому что нет устаревшей кодировки [кроме нескольких вьетнамских кодировок] используются оба), но нормализация совместимости будет. Подумайте, как знак килограмма" kg", который появляется в некоторых восточноазиатских кодировках (или полуширине/полноширине катакана и алфавит), или лигатура "fi" в MacRoman.

посмотреть http://unicode.org/reports/tr15/ для более подробной информации.


обычные формы (Unicode, а не базы данных) имеют дело в первую очередь (исключительно?) с символами, имеющими диакритические метки. Unicode предоставляет некоторые символы с" встроенными " диакритическими знаками, такими как U+00C0, "Латинская столица A с Grave". Тот же символ может быть создан из " Латинской столицы A "(U+0041) с" сочетанием серьезного акцента " (U+0300). Это означает, что даже если две последовательности производят один и тот же результирующий символ, байтовое сравнение покажет, что они полностью отличающийся.

нормализация-это попытка справиться с этим. Нормализация гарантирует (или, по крайней мере, пытается), что все символы кодируются одинаково-либо все используют отдельную комбинирующую диакритическую метку, где это необходимо, либо все используют одну кодовую точку, где это возможно. С точки зрения сравнения, на самом деле не имеет значения, что вы выбираете-почти любая нормализованная строка будет правильно сравниваться с другой нормализованной строкой.

в этом case, "совместимость" означает совместимость с кодом, который предполагает, что одна кодовая точка равна одному символу. Если у вас есть такой код, вы, вероятно, хотите использовать обычную форму совместимости. Хотя я никогда не видел его прямо, имена нормальных форм подразумевают, что консорциум Unicode считает предпочтительным использовать отдельные комбинирующие диакритические метки. Это требует большего интеллекта для подсчета фактических символов в строке (а также таких вещей, как разрыв строки интеллигентно), но более разносторонне.

Если вы в полной мере используете ICU, скорее всего, вы хотите использовать каноническую нормальную форму. Если вы пытаетесь написать код самостоятельно, который (например) предполагает, что кодовая точка равна символу, вам, вероятно, нужна нормальная форма совместимости, которая делает это как можно чаще.


Если две строки unicode канонически эквивалентны, строки действительно одинаковы, только с использованием разных последовательностей unicode. Например, Ä можно представить либо с помощью символа Ä, либо с помощью комбинации A и ◌.

Если строки эквивалентны только совместимости, строки не обязательно одинаковы, но они могут быть одинаковыми в некоторых контекстах. Е. Г. ФФ можно рассматривать так же, как ФФ.

Итак, если вы сравниваете строки, вы должны использовать canonical эквивалентность, потому что эквивалентность совместимости не является реальной эквивалентностью.

но если вы хотите отсортировать набор строк, возможно, имеет смысл использовать эквивалентность совместимости, поскольку они почти идентичны.


является ли каноническая эквивалентность или эквивалентность совместимости более актуальной для вас, зависит от вашего приложения. ASCII-образ мышления о сравнении строк примерно соответствует канонической эквивалентности, но Unicode представляет собой множество языков. Я не думаю, что можно с уверенностью предположить, что Unicode кодирует все языки таким образом, чтобы вы могли относиться к ним так же, как к западноевропейским ASCII.

рисунки 1 и 2 приведите хорошие примеры двух типов эквивалентность. При эквивалентности совместимости похоже, что одно и то же число в суб - и супер - скриптовой форме будет сравниваться равным. Но я не уверен, что решаю ту же проблему, что и курсивная арабская форма или повернутые символы.

трудная правда обработки текста Unicode заключается в том, что вам нужно глубоко подумать о требованиях к обработке текста вашего приложения, а затем обратиться к ним, а также с помощью доступных инструментов. Это напрямую не касается вашего вопроса, но более подробный ответ потребует лингвистических экспертов для каждого из языков, которые вы ожидаете поддержать.


это на самом деле довольно проста. UTF-8 фактически имеет несколько разных представлений одного и того же"характера". (Я использую символ в кавычках, так как в байтах они разные, но практически они одинаковы). Пример приведен в связанном документе.

символ " Ç " может быть представлен как последовательность байтов 0xc387. Но он также может быть представлен C (0x43), за которым следует последовательность байтов 0x8ccca7. Поэтому можно сказать, что 0xc387 и 0x438ccca7 такие же характер. Причина, которая работает, заключается в том, что 0x8ccca7 является комбинирующей меткой; то есть он принимает символ перед ним (a C здесь), и изменяет его.

теперь, что касается разницы между канонической эквивалентностью и эквивалентностью совместимости, нам нужно посмотреть на символы в целом.

есть 2 типа символов, те, которые передают смысл через стоимостью, и те, которые берут другого персонажа и изменяют его. Поэтому 9 является значимым характер. Супер-сценарий ⁹ принимает это значение и изменяет его по презентации. Таким образом, канонически они имеют разные значения, но они по-прежнему представляют собой базовый характер.

таким образом, каноническая эквивалентность-это когда последовательность байтов отображает один и тот же символ с тем же значением. Эквивалентность совместимости - это когда последовательность байтов отображает другой символ с тем же базовым значением (даже если он может быть изменен). Поэтому 9 и ⁹ совместимость эквивалент с они оба означают "9", но не канонически эквивалентны, поскольку они не имеют одного и того же представления...

надеюсь, что это поможет...


проблема сравнивать строки: две строки с содержимым, эквивалентным для большинства приложений, могут содержать различные последовательности символов.

посмотреть каноническая эквивалентность Юникода: если алгоритм сравнения прост (или должен быть быстрым), то эквивалентности Юникод не выполнено. Эта проблема возникает, например, в XML-каноническом сравнении, см. http://www.w3.org/TR/xml-c14n

чтобы избежать этой проблемы... Какой стандарт использовать? "расширенной кодировке utf8" или "в компактном формате utf8"?
Используйте " ç "или" c+◌."?

W3C и другие (ex. имена файлов) предложите использовать " составленный как канонический "(имейте в виду C" самых компактных " коротких строк)... Итак,

стандарт C! в сомнении используйте NFC

для совместимости, и для "соглашение по конфигурации" выбор рекомендуется использовать NFC, чтобы "канонизировать" внешние строки. Для хранения канонического XML, например, сохраните его в "FORM_C". От организации W3C CSV на веб-рабочей группы также рекомендую NFC (раздел 7.2).

PS: de "FORM_C" является формы по умолчанию в большинстве библиотек. Бывший. в нормализаторе PHP.isnormalized ().


Ther термин "композиция форма" (FORM_C) используется для оба, чтобы сказать, что "строка в C-каноническая форма" (результат трансформации NFC) и сказать, что используется преобразование алгоритма... См.http://www.macchiato.com/unicode/nfc-faq

(...) каждая из следующих последовательностей (первые две являются односимвольными последовательностями) представляют один и тот же символ:

  1. U + 00C5 (Å ) ЛАТИНСКАЯ ЗАГЛАВНАЯ БУКВА A С КОЛЬЦОМ Выше
  2. U+212B ( Å ) ЗНАК АНГСТРЕМА
  3. U + 0041 (A ) ЛАТИНСКАЯ ЗАГЛАВНАЯ БУКВА A + U+030A () КОМБИНИРУЯ КОЛЬЦО ВЫШЕ

эти последовательности называются канонически эквивалентны. Первая из этих форм называется NFC-для нормализации формы C, где C - для композиция. (...) Функция, преобразующая строку S в форму NFC, может быть сокращена как toNFC(S), в то время как тот, который проверяет, находится ли S В NFC, сокращается как isNFC(S).


Примечание: для проверки нормализации маленьких строк (чистые ссылки UTF-8 или XML-сущности) вы можете использовать этот тест / нормализовать онлайн-конвертер.