You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
147 lines
4.3 KiB
147 lines
4.3 KiB
/* |
|
Natural order sorting of strings which contains numbers. |
|
|
|
SPDX-FileCopyrightText: 2007 Tobias Koenig <tokoe@kde.org> |
|
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only |
|
based on the natural order code by Martin Pool <mbp sourcefrog net> |
|
*/ |
|
|
|
#include "qnatsort.h" |
|
|
|
static int compare_right(const QString &leftStr, int left, const QString &rightStr, int right) |
|
{ |
|
int bias = 0; |
|
|
|
/** |
|
* The longest run of digits wins. That aside, the greatest |
|
* value wins, but we can't know that it will until we've scanned |
|
* both numbers to know that they have the same magnitude, so we |
|
* remember it in BIAS. |
|
*/ |
|
for (;; left++, right++) { |
|
if (left >= leftStr.length() && right < rightStr.length()) |
|
return -1; |
|
else if (right >= rightStr.length() && left < leftStr.length()) |
|
return +1; |
|
else if (right >= rightStr.length() && left >= leftStr.length()) |
|
return bias; |
|
else if (!leftStr[left].isDigit() && !rightStr[right].isDigit()) |
|
return bias; |
|
else if (!leftStr[left].isDigit()) |
|
return -1; |
|
else if (!rightStr[right].isDigit()) |
|
return +1; |
|
else if (leftStr[left] < rightStr[right]) { |
|
if (!bias) |
|
bias = -1; |
|
} else if (leftStr[left] > rightStr[right]) { |
|
if (!bias) |
|
bias = +1; |
|
} else if (leftStr[left].isNull() && rightStr[right].isNull()) |
|
return bias; |
|
} |
|
|
|
return 0; |
|
} |
|
|
|
static int compare_left(const QString &leftStr, int left, const QString &rightStr, int right) |
|
{ |
|
/** |
|
* Compare two left-aligned numbers: the first to have a |
|
* different value wins. |
|
*/ |
|
for (;; left++, right++) { |
|
if (left >= leftStr.length() && right < rightStr.length()) |
|
return -1; |
|
else if (right >= rightStr.length() && left < leftStr.length()) |
|
return +1; |
|
else if (right >= rightStr.length() && left >= leftStr.length()) |
|
return 0; |
|
else if (!leftStr[left].isDigit() && !rightStr[right].isDigit()) |
|
return 0; |
|
else if (!leftStr[left].isDigit()) |
|
return -1; |
|
else if (!rightStr[right].isDigit()) |
|
return +1; |
|
else if (leftStr[left] < rightStr[right]) |
|
return -1; |
|
else if (leftStr[left] > rightStr[right]) |
|
return +1; |
|
} |
|
|
|
return 0; |
|
} |
|
|
|
static int natural_order_compare(const QString &leftStr, const QString &rightStr, bool fold_case) |
|
{ |
|
if (leftStr.isEmpty() && rightStr.isEmpty()) |
|
return 0; |
|
|
|
int ai, bi; |
|
QChar ca, cb; |
|
int fractional, result; |
|
|
|
ai = bi = 0; |
|
const int aSize = leftStr.size(); |
|
const int bSize = rightStr.size(); |
|
|
|
while (true) { |
|
ca = leftStr[ai]; |
|
cb = rightStr[bi]; |
|
|
|
/* skip over leading spaces or zeros */ |
|
while (ca.isSpace() && ++ai < aSize) |
|
ca = leftStr[ai]; |
|
|
|
while (cb.isSpace() && ++bi < bSize) |
|
cb = rightStr[bi]; |
|
|
|
/* process run of digits */ |
|
if (ca.isDigit() && cb.isDigit()) { |
|
fractional = (ca == QLatin1Char('0') || cb == QLatin1Char('0')); |
|
|
|
if (fractional) { |
|
if ((result = compare_left(leftStr, ai, rightStr, bi)) != 0) |
|
return result; |
|
} else { |
|
if ((result = compare_right(leftStr, ai, rightStr, bi)) != 0) |
|
return result; |
|
} |
|
} |
|
|
|
if (ca.isNull() && cb.isNull()) { |
|
/* The strings compare the same. Perhaps the caller |
|
will want to call strcmp to break the tie. */ |
|
return 0; |
|
} |
|
|
|
if (fold_case) { |
|
ca = ca.toUpper(); |
|
cb = cb.toUpper(); |
|
} |
|
|
|
if (ca < cb) |
|
return -1; |
|
else if (ca > cb) |
|
return +1; |
|
|
|
++ai; |
|
++bi; |
|
if (aSize == ai) { |
|
return aSize <= bSize ? -1 : 1; |
|
} |
|
if (bSize == bi) { |
|
return bSize <= aSize ? 1 : -1; |
|
} |
|
} |
|
} |
|
|
|
bool caseSensitiveNaturalOrderLessThen(const QString &left, const QString &right) |
|
{ |
|
return (natural_order_compare(left, right, false) < 0); |
|
} |
|
|
|
bool caseInsensitiveNaturalOrderLessThen(const QString &left, const QString &right) |
|
{ |
|
return (natural_order_compare(left, right, true) < 0); |
|
}
|
|
|