PHP 8.4.2 Released!

strnatcmp

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

strnatcmpСравнивает строк алгоритмом natural order

Описание

strnatcmp(string $string1, string $string2): int

Функция реализует алгоритм сравнения, который упорядочивает буквенно-цифровые строки подобно тому, как это сделал бы человек, такой алгоритм называется natural ordering. Функция учитывает регистр при сравнении строк.

Список параметров

string1

Первая строка.

string2

Вторая строка.

Возвращаемые значения

Функция возвращает значение меньше 0, если строка string1 меньше строки string2; значение больше 0, если строка string1 больше строки string2, и 0, если строки равны. Из значения возврата невозможно надёжно вывести конкретное значение, кроме знака числа.

Список изменений

Версия Описание
8.2.0 Функция больше не гарантирует возврат разницы strlen($string1) - strlen($string2), когда длины строк не равны, но теперь вместо этого иногда возвращает -1 или 1.

Примеры

Следующий параграф приводит пример, который показывает отличие этого алгоритма от обычных функций сравнения наподобие функции strcmp():

<?php

$arr1
= $arr2 = array("img12.png", "img10.png", "img2.png", "img1.png");

echo
"Стандартный алгоритм сравнения\n";
usort($arr1, "strcmp");
print_r($arr1);

echo
"\nАлгоритм \"natural order\"\n";
usort($arr2, "strnatcmp");
print_r($arr2);

?>

Результат выполнения приведённого примера:

Стандартный алгоритм сравнения
Array
(
    [0] => img1.png
    [1] => img10.png
    [2] => img12.png
    [3] => img2.png
)

Алгоритм "natural order"
Array
(
    [0] => img1.png
    [1] => img2.png
    [2] => img10.png
    [3] => img12.png
)
Подробнее об алгоритме рассказывает страница «» Сравнение строк в естественном порядке».

Смотрите также

  • preg_match() - Выполняет проверку на соответствие регулярному выражению
  • strcasecmp() - Сравнивает строки без учёта регистра в бинарно безопасном режиме
  • substr() - Возвращает подстроку
  • stristr() - Регистронезависимый вариант функции strstr
  • strcmp() - Сравнивает строки в бинарно-безопасном режиме: как последовательности байтов
  • strncmp() - Сравнивает первые n символов строк в бинарно безопасном режиме
  • strncasecmp() - Сравнивает первые n символов строк без учёта регистра в бинарно-безопасном режиме
  • strnatcasecmp() - Сравнивает строки без учёта регистра по алгоритму natural order
  • strstr() - Находит первое вхождение подстроки
  • natsort() - Сортирует массив, для чего использует алгоритм «естественной сортировки»
  • natcasesort() - Сортирует массив алгоритмом естественной сортировки (natural order) без учёта регистра символов

Добавить

Примечания пользователей 4 notes

up
6
in dot games dot mq at gmail dot com
8 years ago
Can also be used with combination of a compare for an array nested value, like

<?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']);} );
up
2
thomas at uninet dot se
18 years ago
There seems to be a bug in the localization for strnatcmp and strnatcasecmp. I searched the reported bugs and found a few entries which were up to four years old (but the problem still exists when using swedish characters).

These functions might work instead.
<?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);
}
?>

The code is not optimized. It was just made to solve my problem.
up
0
chris at ocproducts dot com
7 years ago
This function has some interesting behaviour on strings consisting of mixed numbers and letters.

One may expect that such a mixed string would be treated as alpha-numeric, but that is not true.

var_dump(strnatcmp('23','123')); →
int(-1)
As expected, 23<123 (even though first digit is higher, overall number is smaller)

var_dump(strnatcmp('yz','xyz')); →
int(1)
As expected, yz>xyz (string comparison, irregardless of string length)

var_dump(strnatcmp('2x','12y')); →
int(-1)
Remarkable, 2x<12y (does a numeric comparison)

var_dump(strnatcmp('20x','12y'));
int(1)
Remarkable, 20x>12y (does a numeric comparison)

It seems to be splitting what is being compared into runs of numbers and letters, and then comparing each run in isolation, until it has an ordering difference.
up
-3
spamspamspam at gmx dot com
6 years ago
Some more remarkable outcomes:

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

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

It's not about localisation:

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

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