How to naturally sort a string like humans do (text & numbers sort the number parts as numbers) in C

1 Answer

0 votes
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>

// Natural sort comparator for qsort
int natural_compare(const void *a, const void *b) {
    const char *pa = *(const char **)a;
    const char *pb = *(const char **)b;

    while (*pa && *pb) {
        if (isdigit((unsigned char)*pa) && isdigit((unsigned char)*pb)) {
            // Both are digits: skip leading zeros
            while (*pa == '0') pa++;
            while (*pb == '0') pb++;

            const char *start_a = pa;
            const char *start_b = pb;

            // Find end of number chunks
            while (isdigit((unsigned char)*pa)) pa++;
            while (isdigit((unsigned char)*pb)) pb++;

            size_t len_a = pa - start_a;
            size_t len_b = pb - start_b;

            // Compare by length first (numeric magnitude)
            if (len_a != len_b) return (len_a < len_b) ? -1 : 1;

            // Same length: compare digits lexicographically
            for (size_t i = 0; i < len_a; i++) {
                if (start_a[i] != start_b[i])
                    return (start_a[i] < start_b[i]) ? -1 : 1;
            }
            // If they are identical numbers, continue to next chunk
        } else {
            // Text comparison (case-insensitive)
            char ca = (char)tolower((unsigned char)*pa);
            char cb = (char)tolower((unsigned char)*pb);

            if (ca != cb) return (ca < cb) ? -1 : 1;
            pa++;
            pb++;
        }
    }

    // One string ended before the other
    if (*pa) return 1;
    if (*pb) return -1;
    
    return 0;
}

int main() {
    const char *items[] = {
        "file1",
        "file10",
        "file2",
        "file20",
        "file3",
        "file11",
        "file100",
        "file21"
    };
    int n = sizeof(items) / sizeof(items[0]);

    qsort(items, n, sizeof(const char *), natural_compare);

    printf("Natural sort result:\n");
    for (int i = 0; i < n; i++) {
        printf("%s\n", items[i]);
    }

    return 0;
}



/*
run:

Natural sort result:
file1
file2
file3
file10
file11
file20
file21
file100

*/

 



answered 4 days ago by avibootz
...