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

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

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

Ответ 1

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

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

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

Когда использовать

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

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

NFD

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

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

NFC

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

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

Юникод также содержит много символов, которые действительно не принадлежат, но были использованы в устаревших наборах символов. 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)) и т.д.

Заключение

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

Ответ 2

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

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

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

Подробнее см. http://unicode.org/reports/tr15/.

Ответ 3

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

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

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

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

Ответ 4

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

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

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

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

Ответ 5

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

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

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

Ответ 6

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

Символ "Ç" может быть представлен в виде последовательности байтов 0xc387. Но он также может быть представлен C (0x43), за которым следует последовательность байтов 0xcca7. Таким образом, вы можете сказать, что 0xc387 и 0x43cca7 - это один и тот же символ. Причина, по которой это работает, заключается в том, что 0xcca7 является комбинированной меткой; то есть он берет символ перед ним (здесь C) и модифицирует его.

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

Существует два типа символов: те, которые передают значение через значение, и те, которые принимают другой символ и изменяют его. 9 является значимым символом. Суперскрипт ⁹ принимает это значение и изменяет его по представлению. Таким образом, канонически они имеют разные значения, но они все еще представляют базовый характер.

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

Ответ 7

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

См. Каноническая эквивалентность Unicode: если алгоритм сравнения прост (или должен быть быстрым), Юникодная эквивалентность не выполняется. Эта проблема возникает, например, при каноническом сравнении 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" является формой по умолчанию в большинстве библиотек. Ex. в PHP normalizer.isnormalized().


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

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

  • U + 00C5 (Å) ЛАТИНСКОЕ КАПИТАЛЬНОЕ ПИСЬМО A С КОЛЬЦОЙ ВЫШЕ.
  • U + 212B (Å) ANGSTROM SIGN
  • U + 0041 (A) ЛАТИНСКОЕ КАПИТАЛ ПИСЬМО A + U + 030A (̊) КОМБИНИРОВАНИЕ КОЛЬЦА ВЫШЕ

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


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