简体   繁体   English

不区分大小写排序

[英]Case-insensitive sort

I wrote a sorting program so that if the optional argument -i is present then the sorting should be done without taking into account lowercase / uppercase letters.我编写了一个排序程序,以便如果存在可选参数-i ,则应该在不考虑小写/大写字母的情况下进行排序。

The program uses the standard library qsort() algorithm;程序使用标准库qsort()算法; case-insensitive option is handled by getopt() if the -i flag is supplied to the program.如果将-i标志提供给程序,则不区分大小写的选项由getopt()处理。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>

/* simple comparison function
   just plain string compare from standard library
   qsort passes to this a pointer to a member of the to be sorted array
   this member is a string, so a cast is needed to double pointer
*/
int simple_cmp(const void *a, const void *b)
{
    return strcmp(*(const char **)a, *(const char **)b);
}

int insensitive_cmp(const void *a, const void *b)
{
    return strcasecmp(*(const char **)a, *(const char **)b);
}

/* natural comparison function
   contrary to the other required sorting methods, standard library does not
   have a function for this (actually there is one for directory contents,
   but it is a specialized function not dedicated to string comparison)
   it acts as a normal comparison as long as there is no digits to compare
   when both strings have digits as the next character, instead of comparing
   them, turn it into a number (all the consecutive digits) and compare that
   number as if it was a single character
*/
int natural_cmp(const void *a, const void *b)
{
    const char *stra = *(const char **)a;
    const char *strb = *(const char **)b;

    while (*stra && *strb)
    {
        if (((*stra < '0') || (*stra > '9')) ||
            ((*strb < '0') || (*strb > '9')))
        {
            if (*stra < *strb)
                return -1;
            else if (*stra > *strb)
                return 1;
            stra++;
            strb++;
        }
        else
        {
            long long na;
            long long nb;
            char *end;
            na = strtoll(stra, &end, 10);
            stra = end;
            nb = strtoll(strb, &end, 10);
            strb = end;
            if (na < nb)
                return -1;
            if (na > nb)
                return 1;
        }
    }
    if (*stra != 0)
        return 1;
    if (*strb != 0)
        return -1;
    return 0;
}


int main(int argc,char *argv[])
{
    int i, iFlag = 0, nFlag = 0, rFlag = 0, nrFlaguri = 0;
    int opt;
    int (*sort_func)(const void *, const void *) = simple_cmp;

    /* getopt will cycle through the parameters searching for optional arguments
       if the specified argument is found store the required configuration
       one cannot parse normal arguments until getopt finished cycling through
       all the arguments
       getopt will rearrange the parameter list, so all positional arguments
       are moved to the end, hence normal processing can be done only after
       all optional arguments are consumed
       if unknonw options are detected exit the program with an error message
       as it is most likely a user error or typo and should be corrected
       to achieve expected results
    */
    while ((opt = getopt(argc, argv, "nri")) != -1)
    {
        switch (opt)
        {
            case 'n':
        nrFlaguri++;
        nFlag = 1;    
                sort_func = natural_cmp;
                break;
        case 'r':
        nrFlaguri++;
        rFlag = 1;
        break;
        case 'i':
        nrFlaguri++;
        iFlag = 1;
        sort_func = insensitive_cmp;
        break;
            default: /* '?' */
                exit(EXIT_FAILURE);
        }
    }
    
    if(argc == optind)
    {
    printf("Only optional parameters have been entered");
    return 0;
    }

    if(nrFlaguri > 1)
    {
    printf("Only one sorting option can be selected");
    return 0;
    }

    /* after rearranging the arguments, optind is updated to reflect the
       starting position of the first non-optional argument
       all parameter processing after getopt finished should start from optind
       instead of 1
    */

    /* quick-sort as implemented in the standard library
       it sorts in-place a given vector of unspecified type elements
       the size of a single element, and the length of vector must be supplied
       along the vector itself
       additionally a comparison function must be specified which can compare
       individual elements of the vector
    */
    qsort(&argv[optind], argc-optind, sizeof(char *), sort_func);
    if (rFlag == 1) {
    for(i=argc-1;i>=optind;i--)
        printf("%s\n",argv[i]);
    }
    else {
    /* displaying sorted parameters one by one */
    for(i=optind;i<argc;i++)
        printf("%s\n",argv[i]);
    }
    return 0;
}

How can I modify the program to run and -n -r -i to do natural sorting without differentiating lowercase and uppercase letters and display in reverse order?如何修改程序运行和-n -r -i不区分大写字母和倒序显示的情况下进行自然排序? Does strcasecmp also need to be adapted? strcasecmp是否也需要适配?

Remove the restriction on command line options that is imposed by nrFlaguri .删除nrFlaguri强加的对命令行选项的限制。 As is, the program does not even allow a reversed case-insensitive sort (2 flags, let alone all 3).事实上,该程序甚至不允许反向不区分大小写的排序(2 个标志,更不用说全部 3 个)。

A quick solution is to make the case-insensitivity flag into a file scope variable, so that the behaviour of the comparison functions can be easily modified.一个快速的解决方案是将不区分大小写的标志放入文件 scope变量中,以便可以轻松修改比较函数的行为。

With this, for simplicity, simple_cmp and insensitive_cmp can be combined into a single function, and natural_cmp can use a helper function to compare characters.有了这个,为简单起见, simple_cmpinsensitive_cmp可以组合成一个 function,而natural_cmp可以使用 helper function 来比较字符。

#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>

static int is_insensitive = 0;

int simple_cmp(const void *a, const void *b)
{
    return (is_insensitive
            ? strcasecmp(*(const char **)a, *(const char **)b)
            : strcmp(*(const char **)a, *(const char **)b)
           );
}

int less_than(char a, char b)
{
    return (is_insensitive
            ? tolower((unsigned char) a) < tolower((unsigned char) b)
            : a < b
           );
}

int natural_cmp(const void *a, const void *b)
{
    const char *stra = *(const char **)a;
    const char *strb = *(const char **)b;

    while (*stra && *strb)
    {
        if (isdigit((unsigned char) *stra) && isdigit((unsigned char) *strb))
        {
            char *end;
            long na = strtoll(stra, &end, 10);
            stra = end;
            long nb = strtoll(strb, &end, 10);
            strb = end;

            if (na < nb)
                return -1;
            if (na > nb)
                return 1;
        }
        else
        {
            if (less_than(*stra, *strb))
                return -1;
            else if (less_than(*strb, *stra))
                return 1;

            stra++;
            strb++;
        }
    }

    if (*stra != 0)
        return 1;
    if (*strb != 0)
        return -1;
    return 0;
}

int main(int argc,char **argv)
{
    int (*sort_func)(const void *, const void *) = simple_cmp;
    int print_reversed = 0;
    int opt;

    while ((opt = getopt(argc, argv, "nri")) != -1)
    {
        switch (opt)
        {
            case 'n':
                sort_func = natural_cmp;
                break;
            case 'r':
                print_reversed = 1;
                break;
            case 'i':
                is_insensitive = 1;
                break;
            default: /* '?' */
                exit(EXIT_FAILURE);
        }
    }

    if (argc == optind)
    {
        fprintf(stderr, "Missing arguments to sort.\n");
        return EXIT_FAILURE;
    }

    qsort(argv + optind, argc - optind, sizeof *argv, sort_func);

    if (print_reversed)
        for (int i = argc - 1; i >= optind; i--)
            printf("%s\n", argv[i]);
    else
        for (int i = optind; i < argc; i++)
            printf("%s\n", argv[i]);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM