RE: Repobrowser - Numeric order filename sorting
From: Gerasimov, Ivan <Ivan.Gerasimov_at_transas.com>
Date: 2006-04-12 14:37:22 CEST
Hello, Hans-Emil!
> I would say that the problem lies in trying to sort the likes of:
> v1.3.2
> v101.3.2
> or
> v-1.1.0
> v-1.11.5
> v-1.11.12
Yes, you are right. Though, in the case you mentioned, the sorting will be done properly, since '.' < '0'.
The problem will arise, if some separator that is "greater" than a digit is used, like:
10v
1v
To handle such cases properly, the routine has to remember the whole numbers that are at the places, where the strings are different.
So, here is the improved version of the sample routine, which solves the problem, mentioned above.
I also tried to make it locale-aware. Additionally, I eliminated the need to convert literal number to integer. This way, huge numbers that will not fit into int can be compared. All the comparisons are done with the CompareString() function from WinAPI.
#define IsCharNumeric(C) (!IsCharAlpha(C) && IsCharAlphaNumeric(C))
bool CompareAlphaNumericLess(LPCTSTR x_str, LPCTSTR y_str)
{
LPCTSTR num_x_begin = x_str, num_y_begin = y_str;
DWORD num_x_cnt = 0, num_y_cnt = 0;
// skip same chars and remember last numeric chars of skipped parts
while ((*x_str || *y_str) && CompareString(LOCALE_USER_DEFAULT, NORM_IGNOREWIDTH, x_str, 1, y_str, 1) == 2 /* equal */ )
{
if (IsCharNumeric(*x_str))
{
++num_x_cnt;
++num_y_cnt;
}
else
{
num_x_begin = CharNext(x_str);
num_y_begin = CharNext(y_str);
num_x_cnt = 0;
num_y_cnt = 0;
}
x_str = CharNext(x_str);
y_str = CharNext(y_str);
}
// parse numeric part of first arg
if (num_x_cnt || IsCharNumeric(*x_str))
{
LPCTSTR x_str_tmp = x_str;
while (IsCharNumeric(*x_str_tmp))
{
++num_x_cnt;
x_str_tmp = CharNext(x_str_tmp);
}
// parse numeric part of second arg
if (num_y_cnt || IsCharNumeric(*y_str))
{
LPCTSTR y_str_tmp = y_str;
while (IsCharNumeric(*y_str_tmp))
{
++num_y_cnt;
y_str_tmp = CharNext(y_str_tmp);
}
bool x_has_less_zeros = (num_x_cnt < num_y_cnt);
while (num_x_cnt < num_y_cnt)
{
if (CompareString(LOCALE_USER_DEFAULT, NORM_IGNOREWIDTH, num_y_begin, 1, TEXT("0"), 1) != 2 /* not equal to '0' */ )
return true;
num_y_begin = CharNext(num_y_begin);
--num_y_cnt;
}
while (num_x_cnt > num_y_cnt)
{
if (CompareString(LOCALE_USER_DEFAULT, NORM_IGNOREWIDTH, num_x_begin, 1, TEXT("0"), 1) != 2 /* not equal to '0' */ )
return false;
num_x_begin = CharNext(num_x_begin);
--num_x_cnt;
}
// here, num_x_cnt == num_y_cnt
int cmp_result = CompareString(LOCALE_USER_DEFAULT, NORM_IGNOREWIDTH, num_x_begin, num_x_cnt, num_y_begin, num_y_cnt);
return cmp_result == 1 /* less */ || (cmp_result == 2 /* equal */ && x_has_less_zeros);
}
}
// otherwise, compare literally
return CompareString(LOCALE_USER_DEFAULT, NORM_IGNOREWIDTH, x_str, -1, y_str, -1) == 1 /* less */ ;
}
Sincerely yours,
Ivan Gerasimov
|
This is an archived mail posted to the TortoiseSVN Dev mailing list.
This site is subject to the Apache Privacy Policy and the Apache Public Forum Archive Policy.