crossplatform.ru

Здравствуйте, гость ( Вход | Регистрация )

 
Ответить в данную темуНачать новую тему
> Натуральная (алфавитно-цифровая) сортировка
Litkevich Yuriy
  опции профиля:
сообщение 7.1.2011, 23:19
Сообщение #1


разработчик РЭА
*******

Группа: Сомодератор
Сообщений: 9669
Регистрация: 9.1.2008
Из: Тюмень
Пользователь №: 64

Спасибо сказали: 807 раз(а)




Репутация:   94  


Тут приспичило сортировать список строк в естественной для человека форме.
полазил по ассистенту - не нашёл. Полазил по интернету - нашёл 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
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение

Быстрый ответОтветить в данную темуНачать новую тему
Теги
Нет тегов для показа


1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0




RSS Текстовая версия Сейчас: 28.4.2024, 8:19