#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
*/