Strnatcmp: примеры (PHP)
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
$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
$s1 = "Chapter 3.1.5";
$s2 = "Chapter 3.10.1";
echo strnatcmp($s1, $s2); // Отрицательное число, т.к. 1 < 10 во второй группе чисел
?>-1
<?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
$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
)Аналоги функции в других языках
Используется функция 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']
Нет встроенной функции. Обычно используют библиотеку 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' ]
Прямого аналога нет. Для сортировки по "естественному" порядку часто прибегают к добавлению нулей или разделению данных.
-- Сортировка может быть некорректной для чисел в строках
SELECT name FROM files ORDER BY name;
-- Результат: file1.txt, file10.txt, file2.txt