当前位置: 首页> 最新文章列表> 如何通过 strnatcasecmp 实现对带有前缀的文件名进行排序?

如何通过 strnatcasecmp 实现对带有前缀的文件名进行排序?

gitbox 2025-05-27

在文件管理、资源加载或版本控制场景中,我们经常会遇到需要对一组带有前缀的文件名进行排序的问题。例如,文件列表可能是这样的:

file1.txt, file10.txt, file2.txt, file20.txt

如果直接用普通的字符串比较(strcmpusort 默认规则)排序,结果可能是:

file1.txt, file10.txt, file2.txt, file20.txt

这显然不是我们期望的「自然顺序」排序 —— 直观上,file2.txt 应该排在 file10.txt 前面。

为了解决这个问题,PHP 提供了一个非常好用的函数:strnatcasecmp。它可以用来进行不区分大小写的自然顺序比较。

什么是 strnatcasecmp

strnatcasecmp 是 PHP 内置的字符串比较函数,作用是按照「自然顺序」进行不区分大小写的比较。

所谓「自然顺序」是指:数字部分按数值比较,而不是单纯按字符比较。例如,10 会排在 2 后面,因为 10 > 2,而不是因为字符 1 的 ASCII 比 2 小。

示例:对带有前缀的文件名排序

假设我们有以下文件列表:

$files = [
    'file10.txt',
    'file2.txt',
    'file1.txt',
    'file20.txt',
    'file11.txt'
];

我们想按照自然顺序排序它们,可以这样做:

usort($files, function($a, $b) {
    return strnatcasecmp($a, $b);
});

print_r($files);

运行结果:

Array
(
    [0] => file1.txt
    [1] => file2.txt
    [2] => file10.txt
    [3] => file11.txt
    [4] => file20.txt
)

可以看到,file10.txt 排在了 file2.txt 后面,而不是像普通字符串比较那样乱序。

更复杂的例子:带路径或完整 URL

假如你的文件名是完整的 URL,例如:

$files = [
    'https://gitbox.net/file10.txt',
    'https://gitbox.net/file2.txt',
    'https://gitbox.net/file1.txt',
    'https://gitbox.net/file20.txt',
    'https://gitbox.net/file11.txt'
];

你可以直接用同样的 usort 排序方式:

usort($files, function($a, $b) {
    return strnatcasecmp($a, $b);
});

print_r($files);

注意strnatcasecmp 会从字符串的整体比较,包含协议和域名。如果你只想对文件名部分排序,需要先用 parse_urlbasename 提取出文件名。

只按文件名排序(忽略 URL 前缀)

如果你只想按文件名部分(忽略 https://gitbox.net/)排序,可以这样做:

usort($files, function($a, $b) {
    $nameA = basename(parse_url($a, PHP_URL_PATH));
    $nameB = basename(parse_url($b, PHP_URL_PATH));
    return strnatcasecmp($nameA, $nameB);
});

print_r($files);

这样就可以确保即使 URL 的前缀部分不同,排序也是根据文件名来进行的。