Simple Alphanumeric Ordering Source Code

Copyright © 2015 by David Wincelberg

Following is a revised version of the function that I presented in my Algorithm Alley article (Dr. Dobbs Journal, October 2000). In this version, the conditions in if-statements evaluate to booleans instead of to integers unless they are functions like isdigit(). This rule makes it easier to read the source code and is in keeping with the practice of languages like Java, which require such conditions to evaluate to booleans. In addition, this function is broken into two functions so that the selection of locale ordering verses comparing lowercase letters is made outside of the sorting loop.

// SNSimpleLib.c -- Alphanumeric Ordering

#include <ctype.h>      // for isdigit, tolower
#include <stdlib.h>     // for atoi
#include <string.h>     // for _strnicoll (Windows)


// Action:  Simple alphanumeric comparisons.
// Notes:   Works when there is a digit in the same starting place in
//          each filename.  Limited to numbers smaller than 2^31,
//          around 2 billion.
int SimpleANCompare (const char *pszName1, const char *pszName2) {
    register const char *pszN1 = pszName1, *pszN2 = pszName2;
    int nTest;

    while (*pszN1 != '\0' && *pszN2 != '\0') {
        if (isdigit (*pszN1) && isdigit (*pszN2)) {
            if ((nTest = atoi (pszN1) - atoi (pszN2)) != 0)
                return nTest;

            // Moves past the numbers
            while (isdigit (*pszN1)) ++pszN1;
            while (isdigit (*pszN2)) ++pszN2;
        }
        else {
            nTest = tolower (*pszN1) - tolower (*pszN2);

            if (nTest != 0)
                return nTest;
            else {
                ++pszN1;  ++pszN2;
            }
        }
    }

    return (*pszN1 - *pszN2);   // One string has ended.
}   // SimpleANCompare


// Action:  Simple alphanumeric comparisons -- locale comparisons.
// Notes:   Works when there is a digit in the same starting place in
//          each filename.  Limited to numbers smaller than 2^31,
//          around 2 billion.
int SimpleANCompareLC (const char *pszName1, const char *pszName2) {
    register const char *pszN1 = pszName1, *pszN2 = pszName2;
    int nTest;

    while (*pszN1 != '\0' && *pszN2 != '\0') {
        if (isdigit (*pszN1) && isdigit (*pszN2)) {
            if ((nTest = atoi (pszN1) - atoi (pszN2)) != 0)
                return nTest;

            // Moves past the numbers
            while (isdigit (*pszN1)) ++pszN1;
            while (isdigit (*pszN2)) ++pszN2;
        }
        else {
            nTest = _strnicoll (pszN1, pszN2, 1);

            if (nTest != 0)
                return nTest;
            else {
                ++pszN1;  ++pszN2;
            }
        }
    }

    return (*pszN1 - *pszN2);   // One string has ended.
}   // SimpleANCompareLC

david dot wincelberg at gmail dot com
(In the above line, change "at" and "dot" to their symbols and remove the spaces to produce my e-mail address.)

Return to main page
Last updated: 21-Dec-2015