PHP的数组排序函数一抓一大把,但真到用的时候,很多人还是分不清谁是谁。今天聊的natcasesort(),名字拆开看就是natural+case+sort:自然排序、忽略大小写。它不像sort()那样把键值全打乱重排,而是保留原来的键值对应关系,只调整顺序。
先给结论:natcasesort()专门用来处理那种“人眼看着应该这样排,但计算机按ASCII排会乱掉”的场景。比如文件名、版本号、编号列表。
一、语法与参数
bool natcasesort ( array &$array )
参数只有一个,就是待排序的数组,而且是引用传递。也就是说函数直接改动原数组,不需要重新赋值。返回值是布尔型,成功true,失败false。
这里有个细节值得注意:引用传递意味着你传进去的数组会被就地修改。如果你还想保留原始顺序,得提前复制一份。我平时写代码就吃过这个亏,排完发现原数组没了,调试半天才反应过来。
二、它和sort()、natsort()到底差在哪
sort()是标准排序,按ASCII码值逐个字符比。数字字符串会出问题,比如"img12"会排在"img2"前面,因为字符'1'小于'2'。
natsort()是自然排序,能识别数字部分,"img2"会排在"img12"前面。但它区分大小写,大写字母ASCII码小,会跑到前面去。
natcasesort()等于在natsort()基础上再加一层忽略大小写。大小写混在一起的文件名、变量名、标签列表,用它就对了。
三、代码号学习编程示例
先看一个基础示例,感受下差异:
<?php
$files = array('IMG0.png', 'img12.png', 'img10.png', 'img2.png', 'img1.png', 'IMG3.png');
$copy = $files;
sort($files);
echo "标准排序:\n";
print_r($files);
natcasesort($copy);
echo "自然排序忽略大小写:\n";
print_r($copy);
?>
标准排序结果里,IMG0、IMG3因为大写跑到前面,img1、img10、img12、img2的顺序也不符合人的直觉。natcasesort()之后,顺序变成IMG0、img1、img2、IMG3、img10、img12,这才是我们翻文件夹时希望看到的排列。
再看一个代码号学习编程里常见的场景,版本号排序:
<?php
$versions = array('code12.php', 'Code22.txt', 'code2.php', 'code3.php', 'Code1.php');
$sorted = $versions;
natcasesort($sorted);
print_r($sorted);
?>
输出会按code1、code2、code3、code12、Code22的顺序走。注意键值并没有被重置,原来是哪个键,排完还是哪个键。这个特性在关联数组里特别有用,比如你有一个id=>文件名的映射,排完还能靠id找回数据。
四、键值保留这件事很关键
很多人第一次用natcasesort()会愣一下:为什么打印出来键是2、0、1、3这种乱序?
因为natcasesort()不重置键。sort()会重置成0、1、2、3,natcasesort()不会。这是设计上的取舍,目的是让你在排序后还能用原来的键去取对应的值。
如果你确实想要重新索引,外面套一层array_values()就行:
<?php
$arr = array('b10', 'A2', 'a1');
natcasesort($arr);
$reindexed = array_values($arr);
print_r($reindexed);
?>
五、本节课程知识要点
-
natcasesort()忽略大小写,natsort()区分大小写,sort()既不自然也不忽略大小写。
-
函数是引用传参,直接改原数组,操作前先备份。
-
键值关系保留,不会重新索引,需要连续索引时配合array_values()。
-
适合文件名、版本号、编号列表等含数字的字符串排序。
-
纯英文单词排序用它也可以,但效果和sort()加CASE_INSENSITIVE标志差不多,没必要硬上。
-
返回布尔值,实际项目中很少接返回值,直接看数组结果就行。
六、个人经验分享
我最早接触这个函数是做图片批量重命名工具。用户上传的图片有IMG001.jpg也有img2.jpg,标准排序出来的顺序用户看着就摇头。换成natcasesort()之后,顺序顺眼了,反馈少了很多。
但有一点要提醒:natcasesort()对中文排序不友好。它底层还是按字符编码走,中文场景该用collator或者自定义比较函数。别指望一个函数包打天下。
如果数组里混了数字和字符串,比如array(10,'2','1'),natcasesort()的结果可能和你预期不一样。数字10和字符串'2'比较时,PHP的类型juggling会插一脚。这种边界情况,建议先统一类型再排。
七、什么时候不用它
如果你需要稳定排序(相同值的元素保持原顺序),natcasesort()不保证这一点。PHP8.0之后sort系列是稳定的,但natcasesort的稳定性官方文档没明确承诺。对稳定性有硬要求,自己写usort加比较逻辑更稳妥。
如果数组元素全是纯数字,直接用sort($arr,SORT_NUMERIC)更快更直接。natcasesort()的自然算法对纯数字来说是杀鸡用牛刀。
八、一个容易踩的坑
natcasesort()比较的是字符串。如果你传进去的是整数数组,PHP会先把它们转成字符串再比。这时候'10'和'9'的比较结果,和你想的数值比较可能不同。所以数字数组别用它,用sort或asort。
<?php
$nums = array(10, 9, 100, 1);
natcasesort($nums);
print_r($nums);
// 结果可能是 1, 10, 100, 9 这种,不是数值顺序
?>
这个坑我在代码号学习编程的学员代码里见过好几次,排查起来其实一句话就能说清:它按字符串比,不按数值比。
九、小结
natcasesort()是一个针对性很强的函数。用对场景,几行代码解决文件名排序的痛点;用错场景,键值乱序、类型转换这些问题会让人头疼。记住三点:忽略大小写、保留键值、自然顺序。剩下的就是多写多试,把边界情况mō清楚。
PHP的数组函数依然是最实用的工具箱之一。natcasesort()不算明星函数,但在特定需求下,它比你自己写比较逻辑省事得多。