2024 日本 PHP 研討會

strnatcmp

(PHP 4, PHP 5, PHP 7, PHP 8)

strnatcmp使用「自然排序」演算法比較字串

說明

strnatcmp(字串 $string1, 字串 $string2): 整數

此函式實作了一個比較演算法,它以人類的方式排序字母數字字串,這被描述為「自然排序」。請注意,此比較區分大小寫。

參數

string1

第一個字串。

string2

第二個字串。

傳回值

如同其他的字串比較函式,若 string1 小於 string2,則回傳 -1;若 string1 大於 string2,則回傳 1;若兩者相等,則回傳 0

更新日誌

版本 說明
8.2.0 此函式現在回傳 -11,而先前則回傳負數或正數。

範例

以下範例顯示此演算法與一般電腦字串排序演算法(用於 strcmp() 中)的差異

<?php
$arr1
= $arr2 = array("img12.png", "img10.png", "img2.png", "img1.png");
echo
"標準字串比較\n";
usort($arr1, "strcmp");
print_r($arr1);
echo
"\n自然排序法字串比較\n";
usort($arr2, "strnatcmp");
print_r($arr2);
?>

以上範例將輸出:

Standard string comparison
Array
(
    [0] => img1.png
    [1] => img10.png
    [2] => img12.png
    [3] => img2.png
)

Natural order string comparison
Array
(
    [0] => img1.png
    [1] => img2.png
    [2] => img10.png
    [3] => img12.png
)
更多資訊請參閱:Martin Pool 的 » 自然排序法字串比較 頁面。

參見

  • preg_match() - 執行正規表達式比對
  • strcasecmp() - 二元安全且不區分大小寫的字串比較
  • substr() - 回傳字串的一部分
  • stristr() - 不區分大小寫的 strstr
  • strcmp() - 二元安全的字串比較
  • strncmp() - 前 n 個字元的二元安全字串比較
  • strncasecmp() - 前 n 個字元二元安全且不區分大小寫的字串比較
  • strnatcasecmp() - 使用「自然排序法」的不區分大小寫的字串比較
  • strstr() - 尋找字串中第一次出現的位置
  • natsort() - 使用「自然排序法」排序陣列
  • natcasesort() - 使用不區分大小寫的「自然排序法」排序陣列

新增註解

使用者貢獻的註解 4 則註解

in dot games dot mq at gmail dot com
7 年前
也可以與比較巢狀陣列值的函式組合使用,例如

<?php
$array
= array(
"city" => "xyz",
"names" => array(
array(
"name" => "Ana2",
"id" => 1
) ,
array(
"name" => "Ana1",
"id" => 2
)
)
);
usort($array["names"], function ($a, $b) { return strnatcmp($a['name'], $b['name']);} );
thomas at uninet dot se
18 年前
strnatcmp 和 strnatcasecmp 的本地化似乎存在錯誤。我搜尋了已回報的錯誤,發現了一些長達四年的記錄(但在使用瑞典語字元時問題仍然存在)。

這些函式或許可以替代使用。
<?php
function _strnatcasecmp($left, $right) {
return
_strnatcmp(strtolower($left), strtolower($right));
}

function
_strnatcmp($left, $right) {
while((
strlen($left) > 0) && (strlen($right) > 0)) {
if(
preg_match('/^([^0-9]*)([0-9].*)$/Us', $left, $lMatch)) {
$lTest = $lMatch[1];
$left = $lMatch[2];
} else {
$lTest = $left;
$left = '';
}
if(
preg_match('/^([^0-9]*)([0-9].*)$/Us', $right, $rMatch)) {
$rTest = $rMatch[1];
$right = $rMatch[2];
} else {
$rTest = $right;
$right = '';
}
$test = strcmp($lTest, $rTest);
if(
$test != 0) {
return
$test;
}
if(
preg_match('/^([0-9]+)([^0-9].*)?$/Us', $left, $lMatch)) {
$lTest = intval($lMatch[1]);
$left = $lMatch[2];
} else {
$lTest = 0;
}
if(
preg_match('/^([0-9]+)([^0-9].*)?$/Us', $right, $rMatch)) {
$rTest = intval($rMatch[1]);
$right = $rMatch[2];
} else {
$rTest = 0;
}
$test = $lTest - $rTest;
if(
$test != 0) {
return
$test;
}
}
return
strcmp($left, $right);
}
?>

程式碼未經最佳化,只是為了解決我的問題而編寫。
chris at ocproducts dot com
7 年前
這個函式在處理包含數字和字母混合的字串時,有一些有趣的行為。

人們可能會預期這樣的混合字串會被視為字母數字字串,但事實並非如此。

var_dump(strnatcmp('23','123')); →
int(-1)
如同預期,23<123(即使第一個數字較大,但整體數字較小)

var_dump(strnatcmp('yz','xyz')); →
int(1)
如同預期,yz>xyz(字串比較,與字串長度無關)

var_dump(strnatcmp('2x','12y')); →
int(-1)
值得注意的是,2x<12y(進行數值比較)

var_dump(strnatcmp('20x','12y'));
int(1)
值得注意的是,20x>12y(進行數值比較)

它似乎將比較的對象拆分成數字和字母的區塊,然後單獨比較每個區塊,直到發現排序差異。
spamspamspam at gmx dot com
6 年前
一些更值得注意的結果

var_dump(strnatcmp("0.15m", "0.2m"));
int(1)

var_dump(strnatcmp("0.15m", "0.20m"));
int(-1)

這與本地化無關

var_dump(strnatcmp("0,15m", "0,2m"));
int(1)

var_dump(strnatcmp("0,15m", "0,20m"));
int(-1)
To Top