標準 strcmp 按 ASCII 碼逐字元比較,導致數字字串排序違反直覺:
$files = ['2.jpg', '10.jpg', '1.jpg']; sort($files); // 標準排序 print_r($files); // Array([0]=>10.jpg [1]=>1.jpg [2]=>2.jpg) // 10 排在 1 前面!
int strnatcmp(string $str1, string $str2)
strnatcasecmp。strcmp:0 相等、<0 較小、>0 較大。$a = '2.jpg'; $b = '10.jpg'; $c = 'jb51.net_1'; $d = 'JB51.NET_2'; echo strcmp($a, $b); // 1 (標準:'1' < '2') echo strnatcmp($a, $b); // -1 (自然:2 < 10) echo strcmp($c, $d); // 1 (標準:'J' < 'j') echo strnatcmp($c, $d); // 1 (自然:_1 < _2,大小寫仍敏感)
$files = ['2.jpg', '10.jpg', '1.jpg', '20.jpg', '3.jpg']; natsort($files); // 保留鍵名 print_r($files); // Array([2]=>1.jpg [0]=>2.jpg [4]=>3.jpg [1]=>10.jpg [3]=>20.jpg) // 不分大小寫 $files2 = ['a1.txt', 'A10.txt', 'A2.txt']; natcasesort($files2);
| 場景 | 推薦函式 | 備註 |
|---|---|---|
| 檔案名稱排序(含數字) | natsort | 最常見用途 |
| 版本號比較(v1.2 vs v1.10) | version_compare | 專門處理版本號格式 |
| 一般字串自然排序 | strnatcmp + usort | 自訂比較邏輯 |
| 多位元組字串 | 不支援 | UTF-8 中文數字混排會錯誤 |
function natcmp_utf8($a, $b) {
// 簡易版:將連續數字轉為固定寬度零填充再 strcmp
$pad = function($m) { return sprintf('%010d', $m[0]); };
$a = preg_replace_callback('/\d+/', $pad, $a);
$b = preg_replace_callback('/\d+/', $pad, $b);
return strcmp($a, $b);
}
usort($utf8Files, 'natcmp_utf8');
strnatcmp 為 C 實作,速度極快,大量排序時優於 PHP 層回呼。ORDER BY CAST(SUBSTRING_INDEX(name, '.', 1) AS UNSIGNED) 等 SQL 技巧預排序。strnatcmp / natsort 是處理「含數字字串排序」的利器,完美解決 10 < 2 的反直覺問題。記住:大小寫敏感、不支援多位元組,中文環境需自行轉碼或改用 Collator (intl 擴充) 進行本地化排序。