Мне нужен отсортированный массив шестнадцатеричных чисел. (В этом случае у меня есть 128-битные числа, закодированные как 32-байтные шестнадцатеричные строки: это IP-адреса, преобразованные в двоичную форму in_addr, а затем преобразованные в шестнадцатеричные: адреса IPv4 были добавлены с "::", чтобы дать один адрес -пространство.) Сортировка с использованием встроенной функции sort() PHP дает неожиданные результаты для некоторых значений:
$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, что функция сортировки всегда должна использовать строки сравнения независимо от того, существуют ли в них числовые значения.