CompareString


Description:
CompareString is a simple function that will compare two strings and tell you how they compare. Unlike using strcmp(), it will take into account any numbers that appear in the strings. For instance, the two strings "Track 2 - Blues" and "Track 10 - Pop" would sort using strcmp with the 10 first. StringCompare sorts them as you might want them sorted, with the 2 first.

The example shows how to sort an array using this function and the standard C function qsort().
 
Code:
int CompareStrings(const void * lpv1, const void * lpv2)
{
    TCHAR * sz1 = (TCHAR*) *(TCHAR**)lpv1;
    TCHAR * sz2 = (TCHAR*) *(TCHAR**)lpv2;
    int nPos1 = -1;
    int nPos2 = -1;
    int nEndPos1;
    int nEndPos2;
    int nResult;

    while(true)
    {
        nPos1 ++;
        nPos2 ++;
        // Make sure we haven't hit the end of 
        //  either of the strings
        if (sz1[nPos1] == 0 && sz2[nPos2] == 0)
        {
            return 0;
        }
        else if (sz1[nPos1] == 0)
        {
            return -1;
        }
        else if (sz2[nPos2] == 0)
        {
            return 1;
        }

        // See if this part of both strings is a number
        if (sz1[nPos1] >= _T('0') && sz1[nPos1] <= _T('9') &&
            sz2[nPos2] >= _T('0') && sz2[nPos2] <= _T('9'))
        {
            // Find the end of each number
            nEndPos1 = nPos1;
            do
            {
                nEndPos1++;
            } while (sz1[nEndPos1] >= _T('0') && 
                sz1[nEndPos1] <= _T('9'));

            nEndPos2 = nPos2;
            do
            {
                nEndPos2++;
            } while (sz2[nEndPos2] >= _T('0') && 
                sz2[nEndPos2] <= _T('9'));

            while (true)
            {
                if (nEndPos1 - nPos1 == nEndPos2 - nPos2)
                {
                    // Both numbers are the same length, just
                    //  compare them
                    nResult = _tcsnicmp(sz1 + nPos1, sz2 + nPos2, 
                                nEndPos1 - nPos1);
                    if (nResult == 0)
                    {
                        nPos1 = nEndPos1 - 1;
                        nPos2 = nEndPos2 - 1;
                        break;
                    }
                    else
                    {
                        return nResult;
                    }
                }
                else if (nEndPos1 - nPos1 > nEndPos2 - nPos2)
                {
                    // First number is longer, so if it's not zero
                    //  padded, it's bigger
                    if (sz1[nPos1] == _T('0'))
                    {
                        nPos1 ++;
                    }
                    else
                    {
                        return 1;
                    }
                }
                else
                {
                    // Second number is longer, so if it's not zero
                    //  padded, it's bigger
                    if (sz2[nPos2] == _T('0'))
                    {
                        nPos2 ++;
                    }
                    else
                    {
                        return -1;
                    }
                }
            }
        }
        else
        {
            // One or both characters is not a number, so
            //  just compare them as a string
            nResult = _tcsnicmp(sz1 + nPos1, sz2 + nPos2, 1);
            if (nResult != 0)
            {
                return nResult;
            }
        }
    }
}
 
Sample Usage:
 
    TCHAR * sz[] = {
        "20 - Twenty",
        "1 - One",
        "10 - Ten (1)",
        "2 - Two",
        "20 - Twenty",
        "15 - Fifteen",
        "1 - One (b)",
        "10 - Ten (2)",
        "3 - Three",
        "10 - Ten (100)",
    };

    qsort(sz, 
        sizeof(sz)/sizeof(TCHAR *), 
        sizeof(TCHAR *), CompareStrings);

    for (int i = 0; i < sizeof(sz) / sizeof(TCHAR *); i ++)
    {
        printf("%s\n", sz[i]);
    }

    /*
    Results:
    1 - One
    1 - One (b)
    2 - Two
    3 - Three
    10 - Ten (1)
    10 - Ten (2)
    10 - Ten (100)
    15 - Fifteen
    20 - Twenty
    20 - Twenty
    */