Правильная сортировка строк, содержащих числа в начале
При стандартной лексикографической сортировке строк, начинающихся с чисел, возникает проблема: система сравнивает их посимвольно, что приводит к некорректному порядку. Например, строки "1 строка", "2 строка", "11 строка" будут расположены как "1 строка", "11 строка", "2 строка", поскольку сравнение происходит по первому символу "1" и "2".
Требуется реализовать сортировку, при которой:
- Сначала извлекается и учитывается полное числовое значение в начале строки.
- Если число отсутствует, сравнение происходит по алфавиту.
- Ожидаемый результат:
"1 строка","2 строка","11 строка".
Проблема текущего решения
Предложенный код использует сравнение только первых символов:
usort($subcats, function ($a, $b) {
return strcmp(mb_substr($a->name, 0, 1), mb_substr($b->name, 0, 1));
});Этот подход не подходит, так как он анализирует исключительно первый символ, игнорируя многозначные числа.
Универсальное решение
Для корректной обработки необходимо реализовать функцию сравнения, которая:
- Извлекает числовой префикс из каждой строки.
- Сравнивает строки сначала по числовому значению (если оно присутствует в обеих).
- Если числа нет или они равны, переходит к лексикографическому сравнению.
Вот пример реализации на PHP с использованием функции usort и пользовательского компаратора:
usort($subcats, function ($a, $b) {
// Извлечение чисел из начала строк
preg_match('/^\d+/', $a->name, $matchesA);
preg_match('/^\d+/', $b->name, $matchesB);
$numA = $matchesA[0] ?? null;
$numB = $matchesB[0] ?? null;
// Если оба значения - числа, сравниваем их численно
if ($numA !== null && $numB !== null) {
if ($numA != $numB) {
return $numA <=> $numB;
}
// Если числа равны, сравниваем полные строки лексикографически
return strcmp($a->name, $b->name);
}
// Если только одно из значений - число, число должно идти первым
if ($numA !== null && $numB === null) {
return -1;
}
if ($numA === null && $numB !== null) {
return 1;
}
// Если чисел нет в обеих строках, стандартное строковое сравнение
return strcmp($a->name, $b->name);
});Этот алгоритм обеспечивает естественную сортировку (natural sort), где числовые префиксы обрабатываются как целые числа, а не как последовательности символов.
Альтернативные подходы
- Использование функции
natsort()илиnatcasesort()для массивов, если требуется сортировка по значениям. - Применение флага
SORT_NATURALв функциях типаsort()илиasort(). - Для более сложных сценариев (например, числа внутри текста) можно рассмотреть функцию
strnatcmp().
Представленное решение является универсальным и корректно обрабатывает смешанные данные, обеспечивая интуитивно понятный порядок сортировки.