C中的自然排序 – “包含数字和字母的字符串数组”

寻找一种经过validation的生产算法。 看到这个例子,但没有在网上或书中找到其他东西。

即file_10.txt> file_2.txt

谢谢。

我假设您已经知道C标准库qsort()函数:

 void qsort(void *base, size_t nel, size_t width, int (*compar)(const void *, const void *); 

最后一个参数是一个函数指针 ,这意味着你可以传递任何函数。 实际上你可以使用strcmp() ,但这会给你ASCIIbetical,你特别想要一个自然排序。

在这种情况下,你可以很容易地写一个:

 #include  int natural(const char *a, const char *b) { if(isalpha(*a) && isalpha(*b)) { // compare two letters } else { if(isalpha(*a)) { // compare a letter to a digit (or other non-letter) } else if(isalpha(*b)) { // compare a digit/non-letter to a letter } else { // compare two digits/non-letters } } } 

如果你早点returnelse一些else可以被清除,但是有一个基本的结构。 检查ctype.h是否有类似isalpha()函数(如果字符是字母表的一部分), isdigit()isspace()等等。

这是一个(测试过的)比较函数来完成这项工作。 它只能理解无符号整数,而不是有符号整数或浮点数:

 #include  #include  /* like strcmp but compare sequences of digits numerically */ int strcmpbynum(const char *s1, const char *s2) { for (;;) { if (*s2 == '\0') return *s1 != '\0'; else if (*s1 == '\0') return 1; else if (!(isdigit(*s1) && isdigit(*s2))) { if (*s1 != *s2) return (int)*s1 - (int)*s2; else (++s1, ++s2); } else { char *lim1, *lim2; unsigned long n1 = strtoul(s1, &lim1, 10); unsigned long n2 = strtoul(s2, &lim2, 10); if (n1 > n2) return 1; else if (n1 < n2) return -1; s1 = lim1; s2 = lim2; } } } 

如果要将其与qsort一起使用,请使用此辅助function:

 static int compare(const void *p1, const void *p2) { const char * const *ps1 = p1; const char * const *ps2 = p2; return strcmpbynum(*ps1, *ps2); } 

你可以按顺序做点什么

 qsort(lines, next, sizeof(lines[0]), compare); 

基本排序函数是标准C qsort() 。 它被参数化以采用比较函数,并且比较函数是您需要编写以执行自然排序的函数。

您的交叉引用问题包括比较函数的C实现。

Google搜索“自然排序c”显示了SourceForge实现。

这是Qt的一个版本,它也支持unicode:

 int strcmpbynum(const QString& s1, const QString &s2) { int i1 = 0; // index in string int i2 = 0; while (true) { if (s2.length() == i2) // both strings identical or s1 larger than s2 return s1.length() == i1 ? 0 : 1; if (s1.length() == i1) return -1; // s1 smaller than s2 unsigned short u1 = s1[i1].unicode(); unsigned short u2 = s2[i2].unicode(); if (u1 >= '0' && u1 <= '9' && u2 >= '0' && u2 <= '9') { // parse both numbers completely and compare them quint64 n1 = 0; // the parsed number quint64 n2 = 0; int l1 = 0; // length of the number int l2 = 0; do { ++l1; n1 = n1 * 10 + u1 - '0'; if (++i1 == s1.length()) break; u1 = s1[i1].unicode(); } while (u1 >= '0' && u1 <= '9'); do { ++l2; n2 = n2 * 10 + u2 - '0'; if (++i2 == s2.length()) break; u2 = s2[i2].unicode(); } while (u2 >= '0' && u2 <= '9'); // compare two numbers if (n1 < n2) return -1; if (n1 > n2) return 1; // only accept identical numbers if they also have the same length // (same number of leading zeros) if (l1 < l2) return -1; if (l1 > l2) return 1; } else { // compare digit with non-digit or two non-digits if (u1 < u2) return -1; if (u1 > u2) return 1; ++i1; ++i2; } } 

}