sort() 唯一十六进制数数组(字符串类型):意外结果


sort() array of unique hexadecimal numbers (string-type): unexpected results

我需要一个十六进制数的排序数组。(在本例中,我将 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 排序函数应始终使用比较字符串,而不管其中是否有数值。