• 2021-2022-1-diocs-Linux系统编程-sort


    20191218 2021-2022-1-diocs-Linux系统编程-sort

    一、任务详情

    1. 用man sort 查看sort的帮助文档
    2. sort常用选项有哪些,都有什么功能?提交相关使用的截图
    3. 如果让你编写sort,你怎么实现?写出伪代码和相关的函数或系统调用

    二、实践过程

    sort帮助文档

    在OpenEuler环境下使用man -k sort,发现并没有找到想要的sort

    直接用man sortman 2 sort也是没有找到
    于是我使用比较万能的sort --help命令来查看sort的帮助文档


    总结sort用法如下

    • sort格式
      sort [-bcdfimMnr][-o<输出文件>][-t<分隔字符>][+<起始栏位>-<结束栏位>][--help][--verison][文件][-k field1[,field2]]
    • sort常用选项
        -b 忽略每行前面开始出的空格字符。
        -c 检查文件是否已经按照顺序排序。
        -d 排序时,处理英文字母、数字及空格字符外,忽略其他的字符。
        -f 排序时,将小写字母视为大写字母。
        -i 排序时,除了040至176之间的ASCII字符外,忽略其他的字符。
        -m 将几个排序好的文件进行合并。
        -M 将前面3个字母依照月份的缩写进行排序。
        -n 依照数值的大小排序。
        -u 意味着是唯一的(unique),输出的结果是去完重了的。
        -o<输出文件> 将排序后的结果存入指定的文件。
        -r 以相反的顺序来排序。
        -t<分隔字符> 指定排序时所用的栏位分隔字符。
        +<起始栏位>-<结束栏位> 以指定的栏位来排序,范围由起始栏位到结束栏位的前一栏位。
        --help 显示帮助。
        --version 显示版本信息。
        [-k field1[,field2]] 按指定的列进行排序。
    
         补充说明:sort可针对文本文件的内容,以行为单位来排序。       
    

    sort实践

    ** sort的工作原理**
    sort将文件的每一行作为一个单位,相互比较,比较原则是从首字符向后,依次按ASCII码值进行比较,最后将他们按升序输出。

    -b
    忽略前空白进行排序(这里的空白是指从第一个可见字符开始比较,不仅仅是忽略前导空格)

    -o
    指定输出文件
    sort默认是把结果输出到标准输出,所以需要用重定向才能将结果写入文件,形如sort filename > newfile。
    但是,如果你想把排序结果输出到原文件中,用重定向就需要使用追加的方式,经过尝试,我发现这样追加只会把原文件直接清空

    如果加上-o进行指定文件输出则可以解决这个问题

    -c
    检查文件是否已排好序,若排好序不进行输出,若未排好序则进行输出。

    对刚刚的文件进行检验发现文件内容并没有发生改变,查找资料后知道需要加-o参数指定排序好的内容的输出文件。

    -n
    按照数值大小排序(若不指定将默认以 ASCII 码的次序排列,并将结果输出到标准输出)

    -f
    将小写字母视为大写字母

    -u
    去除重复元素

    可以发现加上-b参数后“ 2333”和“2333”也只保留了第一个

    -d
    经按照英文字母、数字及空格字符排序

    -r
    倒序排序(sort默认的排序方式为升序排列)

    -t

    stu.txt文件中每一列以空格隔开,第一列是学号,第二列是姓名,第三列是寝室号,第四列是体育爱好
    可是直接在-t多打一个空格sort命令并不能识别

    只需要用引号(双引号、单引号都可以)将空格括起来即可解决

    注意此时是按照第一列的内容排序的

    -k
    在不加该参数时,sort默任按照第一列文件内容排序,如果需要指定则需要通过-k 列数实现

    注意这里的列数是从1开始的

    -m
    将多个排好序的文件合并

    sort实现思路

    首先,对sort中常用参数做一个分类,发现只有-o参数和-c不能同时存在,其余基本上都可以组合使用。
    用正则表达式实现命令行中可以在任意位置输入参数,
    其中还要注意sort中的一些默认值:-k参数缺省时默认按照第一列对文件进行排列,-t缺省时默认' '分隔,-n缺省时默认按字典顺序升序排列……
    思路比较清晰一点、比较好实现的参数像
    -b,在读取字符串或者文件时如果遇到不可见字符就跳过即可;
    -n,用stdlib库中的atoi、atol把字符串转成整数或者atof把字符串转换成双精度浮点数,再进行排序即可;
    -f,将所有读到的字符全部转换成大写字母即可(一个islower判断是否为小写,如果是则转成大写即+32);
    -r,将排序条件改成大的在前即可;
    -u,先把文件中所有内容按行读进来(或者从键盘一行一行读入),两层循环遍历一遍所有内容,每次循环用strcmp函数查重,如果相同则去掉后一个(将其置为NULL或''),之后再进行排序;
    -h/H 、--help,输出各参数及其用法、格式说明,退出;
    -t,在读取该参数后紧接着再读入一个字符(可以用单引号括起来)作为每列的分隔符;
    -k,在读取该参数后紧接着再读入一个整数,表示要依据第几列进行排序……
    以上所有排序都可以使用C语言自带的qsort函数void qsort(void* base,size_t num,size_t width,int(__cdecl*compare)(const void*,const void*));实现,其中最后一个参数为自定义的cmp函数(排序规则),返回一个整型的数。
    其中的难点包括文件操作、参数的读取(要考虑到用户输入参数位置比较随意的特点)
    我在网上找到了一份代码,结合自己的理解,最后实现了-t、-n、-r、f、-h、-k几个参数(实现的-k参数后接的是指定列数-1),并可以叠加运行,处理的对象是一个文件中的内容。
    这里展示部分代码的关键部分,完整代码已上传至我的码云仓库:第四周实践代码
    mysort.c

    static void sort_usage_exit(int status)
    {
        if(status != 0)
        {
            fprintf(stderr, "Try '%s --help' for more infomation
    ",
                    program_name);
        }
        else
        {
            printf("Usage: %s   [OPTION] FILE
    ", program_name);
            printf("-n              Sort by number instead of string
    ");
            printf("-r              Reverse sort
    ");
            printf("-t,             Separator, default is '\t'
    ");
            printf("-k,             Sort by which sector, default is 0
    ");
            printf("-f,             Ignore case
    ");
            printf("-h(-H)  --help  Show help information
    ");
        }
    
        exit(status);
    }
    
    static void init_data()
    {
        memset(&g_filedata, 0, sizeof(g_filedata));
    }
    
    static void init_option(struct sort_option *op)
    {
        op->n = 0;
        op->r = 0;
        op->t = '	';
        op->k = 0;
        op->f = 0;
    }
    
    static void fill_t(struct sort_option *op, const char *str)
    {
        if(strlen(str) > 1)
        {
            fprintf(stderr,
                    "[%s]is error, only set one charactor
    ",
                    str);
            exit(1);
        }
        op->t = str[0];
    }
    
    static void fill_k(struct sort_option *op, char *str)
    {
        if(!is_digit(str, strlen(str)))
        {
            fprintf(stderr,
                    "[%s] is not a number
    ",
                    str);
            exit(1);
        }
    
        op->k = atoi(str);
    }
    
    static size_t get_simfile_size(const char *file)
    {
        struct stat         stabuf;
    
        if(stat(file, &stabuf) != 0)
        {
            fprintf(stderr,
                    "stat [%s] error[%s]
    ",
                    file, strerror(errno));
            exit(1);
        }
    
        if(!S_ISREG(stabuf.st_mode))
        {
            fprintf(stderr,
                    "file [%s] is not a simple file
    ",
                    file);
            exit(1);
        }
    
        return stabuf.st_size;
    }
    
    static int fill_line(const char *token)
    {
        size_t              index = g_filedata.used;
    
        if(index == MAX_LINE_NUM)
            return 1;
    
        g_filedata.dataarr[index].base = (char *)token;
        g_filedata.dataarr[index].size = strlen(token);
        g_filedata.dataarr[index].line_no = g_filedata.used++;
    
        return 0;
    }
    
    static int fill_data(char *pdata)
    {
        const char          *sep = "
    ";
        char                *token;
    
        init_data();
        token = strtok(pdata, sep);
        while(token != NULL)
        {
            if(fill_line(token))
                break;
            token = strtok(NULL, sep);
        }
    
        return 0;
    }
    
    static void pr_sorteddata()
    {
        int             i;
    
        for(i = 0; i < g_filedata.used; ++i)
        {
            if(write(STDOUT_FILENO, g_filedata.dataarr[i].base, g_filedata.dataarr[i].size) != g_filedata.dataarr[i].size)
                perror("write");
            if(write(STDOUT_FILENO, "
    ", 1) != 1)
                perror("write2");
        }
    
    }
    
    static void get_field(char *buf)
    {
        char            sep[2];
        char            *token;
        int             field_num = (int)g_op.k;
    
        sprintf(sep, "%c", g_op.t);
    
        token = strtok(buf, sep);
        while(token != NULL && field_num-- > 0)
        {
            token = strtok(NULL, sep);
        }
        
        if(token){
            memmove(buf, token, strlen(token)); 
            buf[strlen(token)] = 0;
        }
        else
            buf[0] = 0;
    }
    
    static int cmp_str(const void *arg1, const void *arg2)
    {
        int         rc;
        char        buf1[MAX_LINE_BUF_SIZE+1], buf2[MAX_LINE_BUF_SIZE+1];
    
        memset(buf1, 0, sizeof(buf1));
        memset(buf2, 0, sizeof(buf2));
    
        snprintf(buf1, MAX_LINE_BUF_SIZE, "%s", *(char **)arg1);
        snprintf(buf2, MAX_LINE_BUF_SIZE, "%s", *(char **)arg2);
    
        /*更新buf1, buf2中内容为需要比较的列 */
        get_field(buf1);
        get_field(buf2);
    
        if(g_op.n &&
           is_digit(buf1, strlen(buf1)) &&
           is_digit(buf2, strlen(buf2)))
            rc = atoi(buf1)-atoi(buf2);
        else if(g_op.f)
            rc = strcasecmp(buf1, buf2);
        else
            rc = strcmp(buf1, buf2);
    
        return g_op.r ? -rc : rc;
    }
    
    static void sort_data()
    {
        qsort(g_filedata.dataarr, g_filedata.used, sizeof(struct one_line), cmp_str);
    }
    
    static int sort(const char*file)
    {
        size_t  filesize = get_simfile_size(file);
        char    *pmapfile = NULL;
        int     fd = -1, err = 0;
    
        if((fd = open(file, O_RDONLY)) < 0)
        {
            perror("open");
            exit(1);
        }
    
        if((pmapfile = (char *)mmap(0, filesize, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0)) == MAP_FAILED)
        {
            perror("mmap");
            exit(1);
        }
        if((err = fill_data(pmapfile)) != 0)
            goto end;
    
        sort_data();
        pr_sorteddata();
    
    end:
        if(pmapfile != NULL)
            munmap(pmapfile, filesize);
        if(fd != -1)
            close(fd);
    
        return err;
    }
    
    

    在OpenEuler下实践

    • -t和-k参数

    • -r参数

    • -h参数

    • -n参数

    • -f参数

  • 相关阅读:
    洛谷——P1196 [NOI2002]银河英雄传说
    Bomb HDU
    LightOJ
    洛谷——P2657 [SCOI2009]windy数
    几校联考——day1题解
    CF997A Convert to Ones
    洛谷——P2574 XOR的艺术
    codevs 3164 质因数分解
    洛谷——P2865 [USACO06NOV]路障Roadblocks
    JS之ClassName属性使用
  • 原文地址:https://www.cnblogs.com/20191218tangqiheng/p/15342457.html
Copyright © 2020-2023  润新知