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

Posted

技术标签:

【中文标题】C中的自然排序 - “字符串数组,包含数字和字母”【英文标题】:Natural sort in C - "array of strings, containing numbers and letters" 【发布时间】:2010-11-23 13:13:12 【问题描述】:

寻找一种经过验证的生产算法。 Did see this example 但在网络或书籍中找不到太多其他内容。

即 文件_10.txt > 文件_2.txt

谢谢。

【问题讨论】:

您对哪种自然语言感兴趣? 【参考方案1】:

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

#include <stdlib.h>
#include <ctype.h>

/* 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一起使用,使用这个辅助函数:

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);

【讨论】:

我认为第一个“return 1”应该是“return -1”。考虑 strcmpbynum ("", "x")。 与声明相反,它没有经过测试,或者应该按字面意思理解声明:> 它只理解无符号整数godbolt.org/z/rr6-jNint main() int rc1 = strcmpbynum("foo1", "foo1_2"); int rc2 = strcmpbynum("foo1_2", "foo1"); int r1 = strcmp("foo1", "foo1_2"); int r2 = strcmp("foo1_2", "foo1"); printf("r1 = %d, r2 = %d, rc1 = %d, rc2 = %d\n", r1, r2, rc1, rc2); // we only care that signs match if (r1 * rc1 &lt;= 0) return -1; if (r2 * rc2 &lt;= 0) return -2; 该声明绝对应该按字面意思理解。【参考方案2】:

基本的排序函数将是标准 C qsort()。它被参数化为一个比较函数,而比较函数就是你需要编写的进行自然排序的东西。

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

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

【讨论】:

我确实看到了源代码的fourge示例,我在Windows上。希望有更多经过良好测试和使用的比较。【参考方案3】:

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

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

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

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

#include <ctype.h>

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
          
      

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

【讨论】:

一个好主意,但有点过于简单化了。不清楚我为什么要费心编写和测试代码...... 如果我们不知道他所说的“自然”是什么意思,并且他忽略了链接的(精心设计和完美便携的)版本,那么很难回答这个问题。【参考方案4】:

这是 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;
    

【讨论】:

以上是关于C中的自然排序 - “字符串数组,包含数字和字母”的主要内容,如果未能解决你的问题,请参考以下文章

TreeSet ------自然排序与定制排序(比较器)

excel表格中的数字有一位数、两位数、三位数,可是排序只按第一位数排,怎样才能按1到10000的自然顺序排呢

Microsoft SQL 2005 中的自然(人类字母数字)排序

一文真正搞懂Java中的自然排序和定制排序,到底升序还是降序

java的comparable接口啥意思

使用android对sqlite中的字母数字值进行自然排序