1

Strnatcmp: примеры (PHP)

Естественное сравнение строк в PHP: работа с функцией strnatcmp
Раздел: Работа со строками
strnatcmp(string string1, string string2): int

Функция strnatcmp в PHP

Функция strnatcmp выполняет сравнение двух строк, используя алгоритм "естественного порядка" (natural ordering). В отличие от обычного побайтового сравнения (как в strcmp), эта функция учитывает числовые значения внутри строк, что делает сортировку более интуитивной для человека.

Когда используется

Функция особенно полезна при сортировке строк, содержащих числа, например, названий файлов (file1.txt, file10.txt, file2.txt), версий программ (1.2.1, 1.10.5) или любых других данных, где числовая последовательность важна для правильного порядка.

Аргументы функции

Функция принимает два обязательных строковых аргумента:

  • $string1 - первая строка для сравнения.
  • $string2 - вторая строка для сравнения.

Возвращает целое число: меньше 0, если $string1 меньше $string2; больше 0, если $string1 больше $string2; 0, если строки равны с точки зрения естественного сравнения.

Краткие примеры использования strnatcmp

Сравнение строк с числами

Ключевое отличие от strcmp:

<?php
$result1 = strcmp("file10.txt", "file2.txt");
$result2 = strnatcmp("file10.txt", "file2.txt");
echo "strcmp: $result1\n"; //  Результат: -1 ("file10.txt" меньше)
echo "strnatcmp: $result2"; // Результат: 1 ("file10.txt" больше)
?>
strcmp: -1
strnatcmp: 1
Равенство строк
<?php
echo strnatcmp("Image 5.jpg", "Image 5.jpg");
?>
0
Сравнение версий программ
<?php
$ver1 = "1.5.2";
$ver2 = "1.12.0";
if (strnatcmp($ver1, $ver2) < 0) {
    echo "Версия $ver1 старше $ver2";
}
?>
Версия 1.5.2 старше 1.12.0

Похожие функции в PHP

  • strnatcasecmp() - аналог strnatcmp, но без учета регистра символов. Предпочтительнее, когда регистр не имеет значения (например, File.txt и file.txt).
  • strcmp() - бинарно-безопасное побайтовое сравнение строк. Используется для точного, чувствительного к регистру сравнения, где числовой порядок не важен.
  • strcasecmp() - побайтовое сравнение без учета регистра.
  • version_compare() - специализирована для сравнения номеров версий PHP и строк, следующих схожим правилам. Более надежна для версий, особенно с альфа/бета-суффиксами.

strnatcmp выбирают, когда нужен общий "человеческий" порядок сортировки для строк, смешанных с числами.

Типичные ошибки

Ожидание булева результата

Функция возвращает целое число, а не true/false.

<?php
// Неправильно
if (strnatcmp("str1", "str2")) { // Условие сработает при -1 или 1
    echo "Строки не равны";
}
// Правильно
if (strnatcmp("str1", "str2") !== 0) {
    echo "Строки не равны";
}
?>
Непонимание знака результата
<?php
$cmp = strnatcmp("2", "10");
if ($cmp < 0) {
    echo "\"2\" меньше \"10\" с точки зрения strnatcmp";
}
?>
"2" меньше "10" с точки зрения strnatcmp
Сравнение нестроковых типов

Функция ожидает строки. Другие типы могут приводиться к строкам, что иногда ведет к неожиданностям.

<?php
// Сравнение строки и числа
var_dump(strnatcmp("10 pixels", 10));
?>
int(1)

Изменения в последних версиях PHP

Начиная с PHP 8.0.0, функция strnatcmp больше не возвращает null при передаче нестроковых аргументов. Вместо этого аргументы приводятся к строковому типу, и если приведение невозможно, генерируется ошибка типа TypeError.

<?php
// Поведение до PHP 8.0.0
// var_dump(strnatcmp("test", [])); // Предупреждение и возврат null
// Поведение в PHP 8+
try {
    strnatcmp("test", []);
} catch (TypeError $e) {
    echo $e->getMessage();
}
?>
strnatcmp(): Argument #2 ($string2) must be of type string, array given

Расширенные примеры

Сортировка массива строк с числами
Пример php
<?php
$items = ["img12.png", "img10.png", "img2.png", "img1.png"];
usort($items, 'strnatcmp');
print_r($items);
?>
Array
(
    [0] => img1.png
    [1] => img2.png
    [2] => img10.png
    [3] => img12.png
)
Сравнение сложных строк

Функция корректно обрабатывает несколько чисел в строке.

Пример php
<?php
$s1 = "Chapter 3.1.5";
$s2 = "Chapter 3.10.1";
echo strnatcmp($s1, $s2); // Отрицательное число, т.к. 1 < 10 во второй группе чисел
?>
-1
Использование в пользовательской сортировке объектов
Пример php
<?php
class Document {
    public function __construct(public string $title) {}
}
$docs = [new Document("Report 5"), new Document("Report 21"), new Document("Report 3")];
usort($docs, fn($a, $b) => strnatcmp($a->title, $b->title));
foreach ($docs as $doc) echo $doc->title . "\n";
?>
Report 3
Report 5
Report 21
Работа с нумерацией страниц
Пример php
<?php
$pages = ["page 9", "page 1", "page 10", "page 2"];
usort($pages, 'strnatcmp');
print_r($pages);
?>
Array
(
    [0] => page 1
    [1] => page 2
    [2] => page 9
    [3] => page 10
)

Аналоги функции в других языках

Python

Используется функция list.sort() или sorted() с аргументом key из модуля natsort или самописным ключом.

# С использованием natsort
from natsort import natsorted
files = ["file10.txt", "file2.txt"]
print(natsorted(files))

# Через functools.cmp_to_key (менее эффективно)
from functools import cmp_to_key
def natural_compare(a, b):
    import re
    convert = lambda text: int(text) if text.isdigit() else text.lower()
    a_key = [convert(c) for c in re.split(r'(\d+)', a)]
    b_key = [convert(c) for c in re.split(r'(\d+)', b)]
    return (a_key > b_key) - (a_key < b_key)
files.sort(key=cmp_to_key(natural_compare))
print(files)
['file2.txt', 'file10.txt']
['file2.txt', 'file10.txt']
JavaScript

Нет встроенной функции. Обычно используют библиотеку natural-compare или реализуют алгоритм аналогично Python.

// Использование localeCompare с numeric
let items = ["file10.txt", "file2.txt"];
items.sort((a, b) => a.localeCompare(b, undefined, {numeric: true}));
console.log(items);
[ 'file2.txt', 'file10.txt' ]
MySQL

Прямого аналога нет. Для сортировки по "естественному" порядку часто прибегают к добавлению нулей или разделению данных.

-- Сортировка может быть некорректной для чисел в строках
SELECT name FROM files ORDER BY name;
-- Результат: file1.txt, file10.txt, file2.txt

PHP strnatcmp function comments

En
Strnatcmp String comparisons using a "natural order" algorithm