2010-08-13 3 views
8

Я нашел это в статье википедии на UTF-8:Сравнение двух байтов [] кодированных строк utf-8 так же, как и сравнение двух строк Unicode?

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

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

Это правда?

ответ

5

Это зависит от того, что вы подразумеваете под «сравнением фактических строк Unicode».

Если вы собираетесь сравнить кодовые точки (как 32-разрядные номера) вместо кодовых кодов UTF-8, тогда ответ будет да. Это даст те же результаты. Отображение из кодовых точек в кодированные байты UTF-8 взаимно однозначно.

Если вы собираетесь выполнить правильное сравнение строк в Юникоде, вместо простого сравнения UTF-8 ответ будет отрицательным. В Unicode могут быть разные способы представления одного и того же символа. Например, Е может быть представлен в (по крайней мере) двумя способами:

  • U+00e9 (LATIN SMALL LETTER E WITH ACUTE) или
  • U+0065 (LATIN SMALL LETTER E) с последующим U+0301 (COMBINING ACUTE ACCENT).

Правильно подобранная функция сравнения Юникода будет считать эти два одинаковыми.

+0

Как отмечает Джон Ханна в своем ответе, в .NET вы сравниваете точки кода как суррогатные пары UTF-16, а не 32-битные числа, поэтому вы фактически получаете разные результаты. Но я принял ваш ответ, потому что вы первыми отметили, что значимое сравнение строк в юникоде не должно основываться на кодовых точках. – Eloff

+0

Я бы не назвал это «правильное» сравнение строк в Юникоде, а сравнение «лингвистических» строк.Существует множество применений сравнения строк, которые не являются лингвистическими, например, внедрение типов данных хранения и поиска и алгоритмов, таких как «quicksort», «двоичный поиск» и т. Д. В таких случаях вам нужен самый быстрый надежный порядок. – hippietrail

+0

Я не согласен с @hippietrail, так как во всех упомянутых случаях хотелось бы, чтобы U + 00e9 был таким же, как U + 0065, за которым следует U + 0301. Существует ли такое «правильное» сравнение строк Unicode? – vy32

3

Нет, это не так.

Например, может быть записан в виде одного (U+00C0 элемента кода латинских заглавной буква А с грависом) или в виде двух кодовых значений (U+0041 латинских заглавных литер А U+0300 КОМБИНИРОВАНИЯ апострофа).

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

+0

Несомненно, эти два кодека будут кодироваться в разные последовательности байтов UTF-8? Или вы говорите, что вы не можете обойти Unicode -> UTF-8 -> Unicode? –

+0

Нет, он говорит, что строка в Unicode NFC и одна и та же строка в NFD (чтобы привести к примерам возможных состояний нормализации) и одна и та же строка, которая не нормализована, не будет иметь одинаковую последовательность кодовых точек. Кроме того, нет смысла говорить о круглом отключении между UTF-8 и Unicode, так как UTF-8 * является * Юникодом, просто сохраненным в определенном порядке байтов. –

+0

Знаете ли вы о функции сравнения Unicode, которая на самом деле ведет себя так? – vy32

5

Да, учитывая, что существует взаимно однозначное сопоставление между байтами последовательностей в кодировке UTF-8 и кодами Unicode.

Тем не менее, есть способ сравнить строки Unicode, кроме того, чтобы посмотреть на необработанные кодовые точки. Если вы просто посмотрите на кодовые точки - или байты UTF-8 - как цифры, то вы пропустите логику сравнения для конкретной культуры.

Чтобы реализовать сравнение и сортировку для определенной культуры на .NET, вы должны использовать стандартные функции сравнения строк.

0

Я нашел это в статье википедии на UTF-8:

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

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

Все это зависит от того, что вы подразумеваете под «фактическими строками Unicode» и что вы подразумеваете под «сравнением». Строки .Net Framework находятся в форме Unicode UTF-16. Простое двоичное сравнение строк UTF-16 будет иметь другой порядок сортировки, чем то же сравнение между строками UTF-8 и UTF-32 (кодовая версия, указанная в цитатах).

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

5

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

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

Важно отметить, что порядковое сравнение строк, предлагаемых .NET, работает на UTF-16, используемом внутри, что не поддерживает заказ кода. Если мы сравним строку с символом U + FF61 и строкой только с символом U + 10002, тогда .NET сохранит последние как суррогатные пары, 0xD800 и 0XDC02.

Следовательно:

string.CompareOrdinal("\U0000ff61", "\U00010002"); 

и

string.Compare("\U0000ff61", "\U00010002", StringComparison.Ordinal); 

как возвращаемые значения большие, чем ноль, даже если бывший ниже стоимости кода точки, чем последний (я использовал форму \ U, а чем форма \ u, чтобы сделать это яснее).

Если по «фактическим строкам Unicode» вы имеете в виду строки .NET UTF-16, тогда ответ на ваш вопрос - это нет, по-разному, к тому, что привело к мысли, что это может сработать.

+0

Увлекательный, я бы получил заказы с UTF-8, и это было бы упорядочением в кодовой точке, в отличие от того, что было получено путем сравнения порядковых чисел в культуре в .NET, просто потому, что .NET использует UTF-16, который не дает кода- точечный порядок. Это тонкий и уверенно превратить какого-то плохого программиста преждевременно в серый цвет: P – Eloff

+1

Обратите также внимание, что культурный инвариант отличается от порядкового. Инвариантная культура - это в значительной степени искусственная культура (которая больше похожа на «среднеатлантическую» англо-культуру, разделяемую между США и Содружеством, чем на любую другую культуру), которая полезна, когда вам нужно принуждать последовательное поведение к культурно правильным обработки. Порядковые сравнения * строго *, когда вам либо нужен произвольный заказ (это культурный мусор, но его быстрый), либо наивно сравнить строки, соответствующие стандарту (например, синтаксический анализ компьютерного кода). –

+1

Возможно, мы могли бы назвать порядковый, «культурно неосведомленный» :) –

Смежные вопросы