2

我有一组数字、特殊字符和字母。我如何对它进行排序,首先是步行 digist,然后是特殊的字符和字母。

$c64 = str_split(
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
);

我试着这样做

array_multisort($l64, SORT_DESC);

但它返回特殊字符、数字和字母

4

2 回答 2

4

这种事情可以以非常“聪明”的方式实现,所以我无法抗拒:

$c64 = str_split(
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
);

$sortValue = function($char) {
    return !ctype_digit($char) << 9 | !ctype_punct($char) << 8 | ord($char);
}

$sortFunction = function($x, $y) use ($sortValue) {
    return $sortValue($x) - $sortValue($y);
};

usort($c64, $sortFunction);

看到它在行动

这个怎么运作

我正在利用ord返回字符的序数值这一事实,这既是普通sort用于对输入进行排序的方法,也被限制在 [0, 255] 范围内——即它使用不超过 8 位价值。

这段代码所做的是获取ord(记住:这是默认值的sort工作方式)的返回值,并用两个额外的信息来增加它:MSB 表示“这个字符不是数字吗?” LSB 表示“这个字符不是标点符号吗?”。

这些位与序数值进行或运算,产生如下所示的 10 位量:

Bit#    10  9  8  7  6  5  4  3  2  1  0
         ^  ^  ^                       ^
         |  |  \-----------+-----------/   
         |  |              \------------- ord
         |  \---------------------------- "not punctuation" bit
         \------------------------------- "not digit" bit

当您将这些值视为整数时会发生什么?显然,对应于非数字的值将大于其他任何值,类似地,对应于非标点符号的值将大于字母等。

因此,通过使用 的结果$x - $y来确定哪个项目更大,我们实际上使数字被认为比其他所有内容都小,标点符号大于数字但小于非数字。这使得sort先放置数字,然后是标点符号,然后是升序排序时的所有其他内容。

最后,参与比较的值是非常重要的ord:对于同一类中的元素(例如数字),我们希望它们的排序顺序与普通sort生成的顺序相同。

于 2013-07-04T15:44:40.557 回答
0
usort($c64, function($a, $b){
    $aord = (is_numeric($a)) ? $a : ord($a);
    $bord = (is_numeric($b)) ? $b : ord($b);
    if ($aord == $bord) return 0;
    return ($aord < $bord) ? -1 : 1;
});
于 2013-07-04T15:37:20.800 回答