如何在 C 中使用 scandir() 不区分大小写?

How to use scandir() in C for case insensitive?

提问人:elvis 提问时间:12/31/2021 最后编辑:chqrlieelvis 更新时间:12/31/2021 访问量:558

问:

我正在学习 C,我有这个实现来对文件和文件夹进行排序,但这并不区分大小写:

#include <dirent.h>
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>

int main(void) {
    struct dirent **namelist;
    int n;

    n = scandir(".", &namelist, NULL, alphasort);
    if (n < 0)
        perror("scandir");
    else {
        printf("Inside else, n = %d\n", n);
        while (n--) {
            printf("%s\n", namelist[n]->d_name);
            free(namelist[n]);
        }
        free(namelist);
    }
}

如果我有 .txt、b.txt、C.txt 和 z.txt,它将按以下顺序排序:C.txt、a.txt、b.txt、z.txt。我希望像这样对大小写进行排序:a.txt、b.txt、C.txt、z.txt

c scandir 排序方向

评论

4赞 kaylum 12/31/2021
那就不要使用 .编写自己的比较器函数。alphasort
2赞 chux - Reinstate Monica 12/31/2021
elvis,“我希望这个排序不区分大小写” --> 如果文件名包含 ,(大写字母和小写字母之间的 ASCCI 章程),文件名的该部分应该在字母之前还是字母之后排序?想要不区分大小写是可以描述相等的(例如 应等同于),但不足以描述顺序。(在和之前或之后。'_"aA_Aa
1赞 chqrlie 1/1/2022
@chux-ReinstateMonica:这确实是一个真正的问题。我想知道是否指定为比较大写或小写转换,或者其他一些替代方法使其具有非传递行为,这是用作比较函数的问题。strcasecmpqsort
0赞 chux - Reinstate Monica 1/1/2022
@chqrlie不在标准库中。与 STL 中不同,以 + 小写字母开头会违反保留名称空间 (7.31.12)。*nix 在野外的实现 我遇到了一个折叠到降低和一个折叠到上折叠,揭示了这个问题。是的,我确信缺乏精确的定义会带来问题和可移植性的风险。更多的想法和快速的替代方案strcasecmp()strqsort()
0赞 chqrlie 1/1/2022
@chux-ReinstateMonica:在 POSIX 中定义,正如您所指出的,手册页指定在 POSIX 语言环境中,strcasecmp() strncasecmp() 的行为就像字符串已转换为小写,然后执行字节比较一样。结果在其他区域设置中未指定。这似乎与(只要所有指针具有相同的表示和调用约定,这是另一个 POSIX 要求。strcasecmpqsort

答:

3赞 chqrlie 12/31/2021 #1

scandir由以下原型定义:

int scandir(const char *restrict dirp,
            struct dirent ***restrict namelist,
            int (*filter)(const struct dirent *),
            int (*compar)(const struct dirent **,
                          const struct dirent **));

该函数按字典顺序对文件名进行排序,因此区分大小写。如果要不区分大小写的排序,请使用不同的比较函数:alphasort

int alphasort_no_case(const struct dirent **a, const struct dirent **b) {
    return strcasecmp((*a)->d_name, (*b)->d_name);
}

和 都是 POSIX 函数:极有可能在支持 和 中定义的系统上可用。scandirstrcasecmpstrcasecmpscandir<strings.h>

修改器版本:

#include <dirent.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>

int alphasort_no_case(const struct dirent **a, const struct dirent **b) {
    return strcasecmp((*a)->d_name, (*b)->d_name);
}

int main(void) {
    struct dirent **namelist;
    int n;

    n = scandir(".", &namelist, NULL, alphasort_no_case);
    if (n < 0) {
        perror("scandir");
    } else {
        printf("Inside else, n = %d\n", n);
        while (n--) {
            printf("%s\n", namelist[n]->d_name);
            free(namelist[n]);
        }
        free(namelist);
    }
    return 0;
}