Что такое нормализованный UTF-8? - PullRequest
121 голосов
/ 28 октября 2011

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

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

Ответы [ 7 ]

169 голосов
/ 29 октября 2011

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

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

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

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

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

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

NFD

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

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

NFC

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

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

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

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

Символы, содержащие информацию о форматировании, заменяются на те, которые не содержат.Например, символ преобразуется в 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 в зависимости от соотношения между пространством и скоростью или в зависимости от того, с чем вы взаимодействуете.

38 голосов
/ 28 октября 2011

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

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

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

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

13 голосов
/ 28 октября 2011

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

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

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

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

5 голосов
/ 28 октября 2011

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

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

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

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

4 голосов
/ 28 октября 2011

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

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

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

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

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

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

4 голосов
/ 28 октября 2011

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

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

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

1 голос
/ 15 августа 2015

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

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

Чтобы избежать этой проблемы ... Какой стандарт использовать?«расширенный UTF8» или «компактный UTF8»?
Используйте «ç» или «c + ◌̧.»?

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

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

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

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


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

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

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

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


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