Тут приспичило сортировать список строк в естественной для человека форме.
полазил по ассистенту - не нашёл. Полазил по интернету - нашёл
The Alphanum Algorithm (реализации на нескольких языках программирования) . Решил сделать на Qt на основе
alphanum.hpp.
/**
* \file alphanum.cpp
* \brief Description
*/
#include "alphanum.h"
/*!
* \fn compare - сравнивает две строки.
* \param l - строка слева.
* \param r - строка справа.
*
* \return
* l<r - отрицательное значение;
* l>r - положительное значение;
* l=r - нуль.
*/
int compare(QString l, QString r)
{
enum Mode{STRING, NUMBER} mode = STRING;
int size;
if (l.size() < r.size())
size = l.size();
else
size = r.size();
int i = 0;
// бежим по обоим строчкам в право до позиции "size-1"
while(i < size){
if (mode == STRING){
QChar lchar, rchar;
bool ldigit, rdigit;
while(i < size){
lchar = l.at(i);
rchar = r.at(i);
ldigit = lchar.isDigit();
rdigit = rchar.isDigit();
// Если оба символа являются числами, то переходим в режим чисел
if (ldigit && rdigit){
mode = NUMBER;
break;
}
if (ldigit) return -1;
if (rdigit) return +1;
// Оба символа - буквы
if (lchar < rchar) return -1;
if (lchar > rchar) return +1;
// Оба символа равны друг другу
i++;
}
}else{//mode == NUMBER
unsigned long long lnum = 0, rnum = 0;
int li = i, ri = i; // локальные индексы
int ld = 0, rd = 0; // цифры
// собираем левое число
while(li < l.size()){
ld = l.at(li).digitValue();
if (ld < 0 ) break;
lnum = lnum*10 + ld;
li++;
}
// собираем правое число
while(ri < r.size()){
rd = r.at(ri).digitValue();
if (rd < 0 ) break;
rnum = rnum*10 + rd;
ri++;
}
long long delta = lnum - rnum;
if (delta) return delta;
// числа одинаковы
mode = STRING;
if (li <= ri)
i=li;
else
i=ri;
}
}
// Сюда попадём если обе строки до позиции "size-1" одинаковы
if (i < r.size()) return -1;
if (i < l.size()) return +1;
// Обе сроки полностью одинаковы
return 0;
}
Как это можно применить? А вот так:
bool alphaNumLessThan(const QString &s1, const QString &s2)
{
if (compare(s1, s2) < 0) return true;
return false;
}
QList<QString> sortByName(QList<QString> list)
{
qStableSort(list.begin(), list.end(), alphaNumLessThan);
return list;
}
sortByName - некая ваша функция, в которой вы используете стандартную функцию сортировки (в примере - qStableSort), но указываете ей свою реализацию алгоритма сравнения (в примере alphaNumLessThan, который и вызывает выше приведённый код натуральной сортировки).
Ограничения оригинальной версии:
Не учитываются дробные числа (знаки препинания не распознаются соответствующим образом).
Особенность версии на Qt:
Т.к. используется QString то нет проблем с сортировкой текста содержащего несколько национальных языков.
Однако сортировка осуществляется в порядке кодов Юникода, т.е. русский после английского.
Пример сортировки (по второму столбцу):
DA2 AD8062AR
VD5 BY614 BY614
VD6 BY614 BY614
VD7 BY614 BY614
VD8 BY614 BY614
VD9 BY614 BY614
VD12 BY614(V) BY614
C2 CAPCHIP_0805 0.1
C22 CAPCHIP_0805 0.1
C25 CAPCHIP_0805 0.1
C26 CAPCHIP_0805 0.1
C28 CAPCHIP_0805 0.1
C6 CAPCHIP_0805 0.1
C7 CAPCHIP_0805 0.1
C16 CAPCHIP_0805 1n
C20 CAPCHIP_0805 6.8 P
C8 CAPCHIP_0805 10n
C9 CAPCHIP_0805 10n
C1 CAPCHIP_0805 15n
C4 CAPCHIP_0805 22p
C5 CAPCHIP_0805 22p
C23 CAPCHIP_1812(V) 1n*3kV
C24 CAPCHIP_1812(V) 1n*3kV
C13 CAPCHIP_1812(V) 10n*1kV
C14 CAPCHIP_1812(V) 10n*1kV
C17 CAPCHIP_1812(V) 10n*1kV
C18 CAPCHIP_1812(V) 10n*1kV
C19 CAPCHIP_1812(V) 10n*1kV
C15 CAPCHIP_A 2.2*10V
C27 CAPCHIP_A 2.2*10V
C10 CAPCHIP_A 2.2*16V
C3 CAPCHIP_B 10,0*16V
C12 CAPCHIP_B 10.0*16V
C11 CAPCHIP_D 10.0*35V
C21 CAPCHIP_D 10.0*35V
VT1 IRFD420
VD1 LL4148 {Value}
VD10 LL4148 {Value}
VD11 LL4148 {Value}
VD2 LL4148 {Value}
VD3 LL4148 {Value}
VD4 LL4148 {Value}
DA1 OPA2364AID
DD1 PIC18F252-E/SO gklm28XX.hex
XP1 PLD2-12(PLT)_YURA {Value}
ZQ1 QUARTZ_HC-49SM 20 MHz
R11 RESCHIP_0805 1M
R14 RESCHIP_0805 1M
R15 RESCHIP_0805 1k
R20 RESCHIP_0805 1k
R24 RESCHIP_0805 1k
R28 RESCHIP_0805 1k
R31 RESCHIP_0805 1k
R29 RESCHIP_0805 2.2k
R1 RESCHIP_0805 4.7k
R4 RESCHIP_0805 10
R8 RESCHIP_0805 10
R19 RESCHIP_0805 10k
R2 RESCHIP_0805 10k
R25 RESCHIP_0805 10k
R26 RESCHIP_0805 10k
R27 RESCHIP_0805 10k
R7 RESCHIP_0805 39k
R12 RESCHIP_0805 51k
R23 RESCHIP_0805 75k
R32 RESCHIP_0805 100k
R13 RESCHIP_0805 510
R30 RESCHIP_0805 620
R16 RESCHIP_0805_1% 5.11k
R17 RESCHIP_0805_1% 24k
R3 RESCHIP_0805_1% 47.5k
R10 RESCHIP_1206 10
R18 RESCHIP_1206 10
R5 RESCHIP_1206 10
R6 RESCHIP_1206 10
R9 RESCHIP_1206 10
R21 RESCHIP_1206 330k
R22 RESCHIP_1206 330k
X6 SOL_CONT_12 {Value}
X1 SOL_CONT_12_12 {Value}
X2 SOL_CONT_12_12 {Value}
X5 SOL_CONT_12_12 {Value}
X7 SOL_CONT_12_12 {Value}
X9 SOL_CONT_12_12 {Value}
X8 SOL_CONT_15_15 {Value}
FV1 T31-A230X_YURA T31-A230X
T1 КВ5_АТ_3