PHP中SCANDIR_SORT排序异常:如何实现类Windows排序效果
解决SCANDIR_SORT_DESCENDING的自然排序问题
你遇到的这个问题其实很常见——scandir()的默认排序是字符串字典序,不是我们直觉里的自然数字排序。举个例子,字符串"10"会被认为比"2"小,因为第一个字符'1'的ASCII码比'2'低,所以降序排序时"2"会排在"10"前面,这就导致第10篇文章跑到底部去了。
下面给你两种靠谱的解决方法,都能实现类似Windows的自然排序效果:
方法一:用自然排序函数处理
先获取所有文件,再用natsort()做自然排序,最后反转成降序(让最新的条目在顶部):
$dir = "news"; // 先获取所有文件,不依赖scandir的排序 $allFiles = array_diff(scandir($dir), array('..', '.')); // 自然排序(按数字大小升序:0,1,2,...,10,11) natsort($allFiles); // 反转成降序,保留键值关联 $allFiles = array_reverse($allFiles, true);
natsort()专门用来处理包含数字的字符串排序,能正确识别"10"比"9"大,完美匹配你要的Windows式排序逻辑。
方法二:自定义排序(更精准可控)
如果想完全基于你命名规则里的newsCounter数值排序,可以用usort()自定义排序规则,直接提取文件名里的数字部分比较:
$dir = "news"; $allFiles = array_diff(scandir($dir), array('..', '.')); // 自定义排序函数,提取开头的counter数值做降序排序 usort($allFiles, function($fileA, $fileB) { // 匹配文件名开头的数字(比如从"10_01_06_2018-093334.html"里拿到10) preg_match('/^(\d+)_/', $fileA, $matchA); preg_match('/^(\d+)_/', $fileB, $matchB); $counterA = (int)$matchA[1]; $counterB = (int)$matchB[1]; // 降序:大的counter排在前面 return $counterB - $counterA; });
这种方法的好处是完全不受文件名其他部分的影响,哪怕以后文件名格式微调,只要开头的counter数字不变,排序就不会出问题。
两种方法都能解决你的问题,选哪种看你的需求——如果文件名格式固定,方法一更简洁;如果需要更精准的控制,方法二更稳妥。
内容的提问来源于stack exchange,提问作者Black
相关产品推荐
相关产品推荐

