Мне нужен отсортированный массив шестнадцатеричных чисел. (В этом случае у меня есть 128-разрядные числа, закодированные как 32-байтовые шестнадцатеричные строки: это IP-адреса, преобразованные в двоичную форму in_addr, а затем преобразованные в шестнадцатеричные: IPv4-адреса были добавлены с «::», чтобы дать один адрес -пространство.) Сортировка с использованием встроенной в PHP функции «sort ()» дает неожиданные результаты для некоторых значений:
$test=array();
$test[]="00000000000000000000000005275087";
$test[]="00000000000000000000000005275104";
$test[]="00000000000000000000000005274E65";
$test[]="00000000000000000000000005274F32";
$test[]="0000000000000000000000000527501C";
\sort($test);
var_dump($test);
→
array(5) {
[0]=> string(32) "00000000000000000000000005275087"[1]=> string(32) "00000000000000000000000005275104"[2]=> string(32) "00000000000000000000000005274E65"[3]=> string(32) "00000000000000000000000005274F32"[4]=> string(32) "0000000000000000000000000527501C"}
Я думаю, что где-то внутри функции sort () должна быть проблема, возможно, вызванная неявным преобразованием типов (непоследовательным образом применяемым в массиве). Тем не менее, в качестве доказательства против идеи, что некоторые отдельные элементы массива сортируются как целые числа или числа с плавающей запятой, в то время как другие сортируются как строки (так что я ожидаю, что результаты будут стабильными, хотя все еще вне порядка сортировки строк); Я обнаружил, что перестановка начальных элементов массива дает разные результаты, а также введение дублирующих записей может побудить функцию sort () выдавать правильные результаты.
Пожалуйста, объясните феномен более подробно и предложите несколько элегантных способов обойти эту проблему! Это ошибка в PHP или «особенность» слабого принуждения типов в PHP?
Полагаю, что-то и то, и другое. Проблема в том, что PHP слишком дружелюбен при сравнении строк, содержащих числовые значения. квотирование документы:
Если вы сравниваете число со строкой или сравнение включает
числовые строки, то каждая строка преобразуется в число и
сравнение выполнено численно.
Теперь рассмотрим это:
var_dump("5275104" < "5274E65"); // bool(true)
var_dump("5274E65" < "5274F32"); // bool(true)
var_dump("5275104" < "5274F32"); // bool(false) - WHAT?
В первом сравнении оба значения являются числовыми строками: первое очевидно, второе из-за E
часть. Они сравниваются как числа, как сказано в документах.
Во втором сравнении, однако, второй операнд не может быть полностью преобразован в число, и теперь значения сравниваются как строки, так что по сути 'E' < 'F'
, Та же самая ситуация в третьем сравнении (строки обрабатываются).
К счастью, это легко исправить:
\sort($test, SORT_STRING);
Флаг сообщает PHP, что функция сортировки всегда должна использовать строки сравнения независимо от того, есть ли в них числовые значения.
Других решений пока нет …