Sort filenames naturally with Qt

后端 未结 6 969
小蘑菇
小蘑菇 2020-12-03 20:34

I am reading a directories content using QDir::entryList(). The filenames within are structured like this:

index_randomNumber.png
6条回答
  •  眼角桃花
    2020-12-03 21:26

    Qt doesn't support natural sorting natively, but it can be quite easily implemented. For example, this can be used to sort a QStringList:

    struct naturalSortCompare {
    
        inline bool isNumber(QChar c) {
            return c >= '0' && c <= '9';
        }
    
        inline bool operator() (const QString& s1, const QString& s2) {
            if (s1 == "" || s2 == "") return s1 < s2;
    
            // Move to the first difference between the strings
            int startIndex = -1;
            int length = s1.length() > s2.length() ? s2.length() : s1.length();
            for (int i = 0; i < length; i++) {
                QChar c1 = s1[i];
                QChar c2 = s2[i];
                if (c1 != c2) {
                    startIndex = i;
                    break;
                }
            }
    
            // If the strings are the same, exit now.
            if (startIndex < 0) return s1 < s2;
    
            // Now extract the numbers, if any, from the two strings.
            QString sn1;
            QString sn2;
            bool done1 = false;
            bool done2 = false;
            length = s1.length() < s2.length() ? s2.length() : s1.length();
    
            for (int i = startIndex; i < length; i++) {
                if (!done1 && i < s1.length()) {
                    if (isNumber(s1[i])) {
                        sn1 += QString(s1[i]);
                    } else {
                        done1 = true;
                    }
                }
    
                if (!done2 && i < s2.length()) {
                    if (isNumber(s2[i])) {
                        sn2 += QString(s2[i]);
                    } else {
                        done2 = true;
                    }
                }
    
                if (done1 && done2) break;
            }
    
            // If none of the strings contain a number, use a regular comparison.
            if (sn1 == "" && sn2 == "") return s1 < s2;
    
            // If one of the strings doesn't contain a number at that position,
            // we put the string without number first so that, for example,
            // "example.bin" is before "example1.bin"
            if (sn1 == "" && sn2 != "") return true;
            if (sn1 != "" && sn2 == "") return false;
    
            return sn1.toInt() < sn2.toInt();
        }
    
    };
    

    Then usage is simply:

    std::sort(stringList.begin(), stringList.end(), naturalSortCompare());
    

提交回复
热议问题