Подтвердить что ты не робот

Что такое Perl "стандартный порядок сравнения строк"?

Это действительно двойной вопрос, мои два конечных цели имеют ответы на:

  • Каков стандартный порядок сравнения строк с точки зрения механики?
  • Какое лучшее имя для этого, чтобы я мог обновить документы?

Документация Perl для sort говорит, что без блока sort используется "стандартный порядок сравнения строк". Но что это за заказ? Для этого должно быть лучшее имя. Для этого вопроса я конкретно имею в виду ситуацию, когда locale не действует, поскольку это определяет его собственный порядок.

В прошлые годы мы обычно называем стандартный порядок сортировки "ASCIIbetically". Это в Learning Perl и многие другие книги. Однако этот термин датирован. Perl поддерживает Unicode начиная с 5.6. Говорить об ASCII - это старая школа. Поскольку Perl также поддерживает Unicode, он знает о символьных строках. В sv.c Perl_sv_cmp знает о locale, bytes и UTF-8. Первые два легко. Но я не уверен в третьем.

/*
=for apidoc sv_cmp

Compares the strings in two SVs.  Returns -1, 0, or 1 indicating whether the
string in C<sv1> is less than, equal to, or greater than the string in
C<sv2>. Is UTF-8 and 'use bytes' aware, handles get magic, and will
coerce its args to strings if necessary.  See also C<sv_cmp_locale>.

=cut
*/

Когда Perl сортирует с использованием UTF-8, что он действительно сортирует? Байт, который кодирует строка, символы, которые он представляет (включая знаки, возможно?) Или что-то еще? Я думаю, что это соответствующая строка в sv.c(строка 6698 для фиксации 7844ec1):

 pv1 = tpv = (char*)bytes_to_utf8((const U8*)pv1, &cur1);

Если я читаю это право (используя мой ржавый C), pv1 принуждается к октетам, превращается в UTF-8, а затем принуждается к символам (в смысле C). Я думаю, что это означает, что он сортирует по кодировке UTF-8 (т.е. Фактические байты, используемые UTF-8 для представления кодовой точки). Другой способ сказать, что он не сортирует графемы. Я думаю, что я почти убедил себя, что читаю это правильно, но некоторые из вас знают об этом больше, чем я.

Отсюда следующая интересная строка - 6708:

 const I32 retval = memcmp((const void*)pv1, (const void*)pv2, cur1 < cur2 ? cur1 : cur2);

Мне кажется, что после того, как он имеет pv1 и pv2, которые были принуждены к char *, теперь они просто сравниваются побайтно, потому что их принуждают к void *. Это то, что происходит с memcmp, похоже, что он просто сравнивает биты на основе различных документов, которые я читал до сих пор? Опять же, мне интересно, чего мне не хватает в поездке из байтов → utf8 → char → байтов, например, как шаг юникодной нормализации. Проверка Perl_bytes_to_utf8 в utf8.c не помогла мне ответить на этот вопрос.

В качестве примечания, мне интересно, это то же самое, что Unicode Collation Algorithm? Если это так, почему существует Unicode:: Collate? По внешнему виду, я не думаю, что Perl sort обрабатывает каноническую эквивалентность.

4b9b3361

Ответ 1

UTF-8 обладает тем свойством, что сортировка строки по байтам по UTF-8 в соответствии с байтовым значением дает тот же порядок, что и его сортировка по кодовому номеру в соответствии с номером кода. То есть, я знаю, не глядя, что UTF-8 представление U + 2345 является лексикографическим после представления UTF-8 U + 1234.

Что касается нормализации, ядро ​​Perl ничего об этом не знает; чтобы получить точную сортировку и сравнение между различными форматами, которые вы хотели бы запустить со всеми вашими строками через Unicode::Normalize и преобразовать их все в одну и ту же нормализацию форма. Я не могу прокомментировать, что лучше всего подходит для какой-либо конкретной цели, главным образом потому, что я понятия не имею.

Также, сортировка и cmp подвержены влиянию locale прагмы, если она используется; он использует порядок сортировки POSIX. Используя use locale, 8-битный язык и уникод все вместе являются рецептом катастрофы, но с использованием use locale, локаль UTF-8 и юникод должны работать с пользой. Я не могу сказать, что я пробовал. Там очень много информации в perllocale и perlunicode в любом случае.

Ответ 2

Я не могу ответить на весь вопрос, поэтому позвольте мне оттолкнуть одну часть:

    const I32 retval = memcmp((const void*)pv1, (const void*)pv2, cur1 < cur2 ? cur1 : cur2);

... выглядит, как только он имеет pv1 и pv2, которые были принудительно привязаны к char *, теперь сравниваются побайтно, потому что они принудительно привязаны к void *. Это то, что происходит с memcmp

В значительной степени. Основные отличия между memcmp и strcmp заключаются в следующем:

  • strcmp остановится, когда увидит NULL (т.е. '\0'), а Perl позволяет скалярам внедрить NULL s
  • memcmp часто выполняется немного быстрее, чем strcmp

Но помимо этого вы получите те же результаты.