From a46fd28ae39d5634337b343d6f45fa6a804a91a6 Mon Sep 17 00:00:00 2001 From: Maganty Rushyendra Date: Fri, 3 Jul 2020 23:47:24 +0800 Subject: [PATCH] Fix natural sort comparison for strings with large numbers Fix errors when comparing strings with large numbers (> INT64_MAX). Comparisons now occur by comparing individual digits, instead of converting to int64_t first. (cherry picked from commit de46c92711f83b14a532702060d17b4269b9e1e9) --- core/ustring.cpp | 59 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 39 insertions(+), 20 deletions(-) diff --git a/core/ustring.cpp b/core/ustring.cpp index 1abfa8c996..78685a44b0 100644 --- a/core/ustring.cpp +++ b/core/ustring.cpp @@ -535,33 +535,52 @@ signed char String::naturalnocasecmp_to(const String &p_str) const { } while (*this_str) { - - if (!*that_str) + if (!*that_str) { return 1; - else if (IS_DIGIT(*this_str)) { - - int64_t this_int, that_int; - - if (!IS_DIGIT(*that_str)) + } else if (IS_DIGIT(*this_str)) { + if (!IS_DIGIT(*that_str)) { return -1; + } - /* Compare the numbers */ - this_int = to_int(this_str); - that_int = to_int(that_str); + // Keep ptrs to start of numerical sequences + const CharType *this_substr = this_str; + const CharType *that_substr = that_str; - if (this_int < that_int) - return -1; - else if (this_int > that_int) - return 1; - - /* Skip */ - while (IS_DIGIT(*this_str)) + // Compare lengths of both numerical sequences, ignoring leading zeros + while (IS_DIGIT(*this_str)) { this_str++; - while (IS_DIGIT(*that_str)) + } + while (IS_DIGIT(*that_str)) { that_str++; - } else if (IS_DIGIT(*that_str)) + } + while (*this_substr == '0') { + this_substr++; + } + while (*that_substr == '0') { + that_substr++; + } + int this_len = this_str - this_substr; + int that_len = that_str - that_substr; + + if (this_len < that_len) { + return -1; + } else if (this_len > that_len) { + return 1; + } + + // If lengths equal, compare lexicographically + while (this_substr != this_str && that_substr != that_str) { + if (*this_substr < *that_substr) { + return -1; + } else if (*this_substr > *that_substr) { + return 1; + } + this_substr++; + that_substr++; + } + } else if (IS_DIGIT(*that_str)) { return 1; - else { + } else { if (_find_upper(*this_str) < _find_upper(*that_str)) //more than return -1; else if (_find_upper(*this_str) > _find_upper(*that_str)) //less than