当前位置: 首页> 最新文章列表> 如何结合 strnatcasecmp 与 array_map 对数组中的字符串进行统一格式化?

如何结合 strnatcasecmp 与 array_map 对数组中的字符串进行统一格式化?

gitbox 2025-05-27

在日常 PHP 编程中,我们经常需要对字符串数组进行排序,但默认的字典序排序(sortusort 等)并不能很好地处理带有数字的字符串。比如 img1.png, img2.png, img10.png 这样的文件名,如果用普通的字符串比较,排序结果会是 img1.png, img10.png, img2.png,显然不符合人类的自然排序习惯。

为了实现“自然排序”,PHP 提供了 strnatcmpstrnatcasecmp 函数,分别对应区分大小写和不区分大小写的自然排序。
另外,当我们对数组排序时,常常还需要对数组中的每个元素统一格式化,比如全部转小写或去掉多余空格,这时候可以用 array_map 来实现。

本文将介绍如何将这两个工具结合起来,对数组中的字符串进行统一格式化后,再进行自然排序。

核心步骤

1?? 准备数据数组
我们以一组文件名为例:

$files = ['Img10.png', 'img2.png', 'IMG1.png', 'img20.png', 'img11.png'];

2?? 使用 array_map 格式化元素
假设我们想把它们全部转为小写:

$formattedFiles = array_map('strtolower', $files);

如果要更复杂的处理(比如去空格、统一扩展名),可以写成匿名函数:

$formattedFiles = array_map(function($item) {
    return strtolower(trim($item));
}, $files);

3?? 自定义排序函数
PHP 的 usort 允许我们用自定义函数排序:

usort($formattedFiles, 'strnatcasecmp');

注意:strnatcasecmp 是一个比较函数,而不是直接用于排序的函数。

完整示例代码

<?php
$files = ['Img10.png', 'img2.png', 'IMG1.png', 'img20.png', 'img11.png'];

// 第一步:统一格式(转小写 + 去空格)
$formattedFiles = array_map(function($item) {
    return strtolower(trim($item));
}, $files);

// 第二步:自然排序(不区分大小写)
usort($formattedFiles, 'strnatcasecmp');

// 输出结果
foreach ($formattedFiles as $file) {
    echo $file . "\n";
}
?>

运行结果:

img1.png
img2.png
img10.png
img11.png
img20.png

更实际的例子:带 URL 的情况

假设我们处理的是一组 URL:

$urls = [
    'https://gitbox.net/File10.html',
    'https://gitbox.net/file2.html',
    'https://gitbox.net/FILE1.html',
    'https://gitbox.net/file20.html',
    'https://gitbox.net/file11.html',
];

我们想按文件名部分排序,可以先提取文件名,再排序:

<?php
$urls = [
    'https://gitbox.net/File10.html',
    'https://gitbox.net/file2.html',
    'https://gitbox.net/FILE1.html',
    'https://gitbox.net/file20.html',
    'https://gitbox.net/file11.html',
];

// 提取文件名部分并绑定到 URL
$mapped = array_map(function($url) {
    $parts = parse_url($url);
    $file = basename($parts['path']);
    return ['url' => $url, 'file' => strtolower($file)];
}, $urls);

// 按文件名自然排序
usort($mapped, function($a, $b) {
    return strnatcasecmp($a['file'], $b['file']);
});

// 输出排序后的 URL
foreach ($mapped as $item) {
    echo $item['url'] . "\n";
}
?>

输出:

https://gitbox.net/FILE1.html
https://gitbox.net/file2.html
https://gitbox.net/File10.html
https://gitbox.net/file11.html
https://gitbox.net/file20.html