[svn.haxx.se] · SVN Dev · SVN Users · SVN Org · TSVN Dev · TSVN Users · Subclipse Dev · Subclipse Users · this month's index

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

 

 
Received on Wed Apr 12 14:37:53 2006

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.