mirror of
https://github.com/qbittorrent/qBittorrent.git
synced 2025-12-21 16:07:23 -06:00
Improve natural sort algorithm
1. Use proper case folding function instead of `toLower()`. 2. Use locale aware comparison instead of comparing unicode code points. Now `a` comes before `A` which is the same as the result from QCollator. A nice side effect is now it properly compares locale specific characters (for example `C`, `Č`). 3. Improve testing. Now the test is runnable and stable on all platforms. PR #20208.
This commit is contained in:
@@ -31,7 +31,6 @@
|
||||
#include <QChar>
|
||||
#include <QString>
|
||||
|
||||
#ifndef QBT_USE_QCOLLATOR
|
||||
int Utils::Compare::naturalCompare(const QString &left, const QString &right, const Qt::CaseSensitivity caseSensitivity)
|
||||
{
|
||||
// Return value <0: `left` is smaller than `right`
|
||||
@@ -45,8 +44,8 @@ int Utils::Compare::naturalCompare(const QString &left, const QString &right, co
|
||||
if ((posL == left.size()) || (posR == right.size()))
|
||||
return (left.size() - right.size()); // when a shorter string is another string's prefix, shorter string place before longer string
|
||||
|
||||
const QChar leftChar = (caseSensitivity == Qt::CaseSensitive) ? left[posL] : left[posL].toLower();
|
||||
const QChar rightChar = (caseSensitivity == Qt::CaseSensitive) ? right[posR] : right[posR].toLower();
|
||||
const QChar leftChar = (caseSensitivity == Qt::CaseSensitive) ? left[posL] : left[posL].toCaseFolded();
|
||||
const QChar rightChar = (caseSensitivity == Qt::CaseSensitive) ? right[posR] : right[posR].toCaseFolded();
|
||||
// Compare only non-digits.
|
||||
// Numbers should be compared as a whole
|
||||
// otherwise the string->int conversion can yield a wrong value
|
||||
@@ -89,8 +88,7 @@ int Utils::Compare::naturalCompare(const QString &left, const QString &right, co
|
||||
}
|
||||
else
|
||||
{
|
||||
return (leftChar.unicode() - rightChar.unicode());
|
||||
return QString::localeAwareCompare(leftChar, rightChar);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -34,24 +34,35 @@
|
||||
// for QT_FEATURE_xxx, see: https://wiki.qt.io/Qt5_Build_System#How_to
|
||||
#include <QtCore/private/qtcore-config_p.h>
|
||||
|
||||
#ifndef QBT_USE_QCOLLATOR
|
||||
// macOS and Windows support 'case sensitivity' and 'numeric mode' natively
|
||||
// https://github.com/qt/qtbase/blob/6.0/src/corelib/CMakeLists.txt#L777-L793
|
||||
// https://github.com/qt/qtbase/blob/6.0/src/corelib/text/qcollator_macx.cpp#L74-L77
|
||||
// https://github.com/qt/qtbase/blob/6.0/src/corelib/text/qcollator_win.cpp#L72-L78
|
||||
#if ((QT_FEATURE_icu == 1) || defined(Q_OS_MACOS) || defined(Q_OS_WIN))
|
||||
#define QBT_USE_QCOLLATOR
|
||||
#define QBT_USE_QCOLLATOR 1
|
||||
#include <QCollator>
|
||||
#else
|
||||
#define QBT_USE_QCOLLATOR 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
class QString;
|
||||
|
||||
namespace Utils::Compare
|
||||
{
|
||||
#ifdef QBT_USE_QCOLLATOR
|
||||
int naturalCompare(const QString &left, const QString &right, Qt::CaseSensitivity caseSensitivity);
|
||||
|
||||
template <Qt::CaseSensitivity caseSensitivity>
|
||||
class NaturalCompare
|
||||
{
|
||||
public:
|
||||
#if (QBT_USE_QCOLLATOR == 0)
|
||||
int operator()(const QString &left, const QString &right) const
|
||||
{
|
||||
return naturalCompare(left, right, caseSensitivity);
|
||||
}
|
||||
#else
|
||||
NaturalCompare()
|
||||
{
|
||||
m_collator.setNumericMode(true);
|
||||
@@ -65,20 +76,8 @@ namespace Utils::Compare
|
||||
|
||||
private:
|
||||
QCollator m_collator;
|
||||
};
|
||||
#else
|
||||
int naturalCompare(const QString &left, const QString &right, Qt::CaseSensitivity caseSensitivity);
|
||||
|
||||
template <Qt::CaseSensitivity caseSensitivity>
|
||||
class NaturalCompare
|
||||
{
|
||||
public:
|
||||
int operator()(const QString &left, const QString &right) const
|
||||
{
|
||||
return naturalCompare(left, right, caseSensitivity);
|
||||
}
|
||||
};
|
||||
#endif
|
||||
};
|
||||
|
||||
template <Qt::CaseSensitivity caseSensitivity>
|
||||
class NaturalLessThan
|
||||
|
||||
Reference in New Issue
Block a user