zoukankan      html  css  js  c++  java
  • Word Count作业

    Word Count作业

    一.个人Gitee地址:https://gitee.com/Changyu-Guo

    二.项目简介

    该项目主要是模拟Linux上面的wc命令,基本要求如下:

    命令格式:

    wc.exe [para] <filename> [para] <filename> ... -o <filename>

    功能:

    wc.exe -c file.c:返回文件file.c的字符数

    wc.exe -w file.c:返回文件file.c的单词总数

    wc.exe -l file.c:返回文件file.c的总行数

    wc.exe -o outputFile.txt:将结果输出到指定文件

    要求:

    -o后面必须跟一个文件

    -c -w -l可以同时出现

    -c -w -l可以合并成 -wcl,即命令可以连写

    如果不指定输出文件,则将结果默认保存在result.txt里面

    三.PSP2.1表格

    PSP2.1PSP阶段预估耗时(分钟)实际耗时(分钟)
    Planning 计划 5 5
    · Estimate · 估计这个任务需要多少时间 5 5
    Development 开发 340 635
    · Analysis · 需求分析(包括学习新技术) 20 30
    · Design Spec · 生成设计文档 30 30
    · Design Review · 设计复审(和同事审核设计文档) 10 15
    · Coding Standard · 代码规范(为目前的开发制定合适的规范) 5 5
    · Design · 具体设计 15 20
    · Coding · 具体编码 200 400
    · Code Review · 代码复审 40 30
    · Test · 测试(自我测试,修改代码,提交修改) 20 30
    Reporting 报告 60 50
    · Test Report · 测试报告 20 15
    · Size Measurement · 计算工作量 10 5
    · Postmortem & Process improvement Plan · 事后总结,并提出过程改进计划 30 30
      合计 405 690

    四.解题思路

    ​ 由于自己对C语言比较熟悉(主要是C语言编译过后就是exe,其他语言还要打包,就直接用C语言写了),因此选择用C语言来实现这个项目。刚拿到题的时候仔细分析了一下,发现在功能上的要求不高,甚至不用校验单词的有效性,凡是以空格和逗号隔开的都算是单词,因此第一次作业的难点应该在于命令行参数的解析上面。

    ​ 接下来我用C语言写了一个简单的demo,尝试着梳理一下程序构建思路,应该如何设计,模块怎样划分。demo中所有的功能都在main函数里面,没有上传到码云。

    写好demo后,大致整理了一下解题思路:

    1.程序执行流程分析

    ​ 根据项目的要求,该程序执行的大体流程为:首先用户执行程序并附带各种参数,程序首先要分析处理各种选项,校验选项的有效性,并将各种参数和对应的文件联系在一起,然后对不同的文件执行该文件对用的各种操作,然后将最终的结果一并保存在输出文件中。

    2.数据结构设计

    ​ 根据对程序执行流程的分析,由于不同的文件对应着不同的操作,因此需要将文件名和其对应的操作绑定在一起,由此想到了用结构体保存一个文件的相关信息,然后使用链表将各个文件连起来。待命令处理完毕后,只需遍历链表,即可对各个文件执行相应的操作。文件的结构体如下:

    // 命令结构体
    // 解析命令时存储相关信息
    struct Node
    {
      bool _c;
      bool _w;
      bool _l;
      bool _hasFile;
      char inFile[100];
      int row;
      int character;
      int words;
      struct Node *next;
    };

    3.模块划分

    根据程序的执行流程,可以将程序划分为以下几个模块:

    (1).主函数

    主函数中主要是一些基本的处理和一些简单的逻辑的处理,负责调用其他函数

    (2).命令处理模块

    ​ 对于用户输入的命令的处理,有很多种办法,其中最常用的就是遍历数组,或者将输入的命令编程字符串,然后解析字符串,我选择的是将用户输入的各种选项和命令拼接成一个字符串,然后遍历整个字符串,并做相应的分析。

    (3).统计模块

    ​ 统计模块主要就是对每个文件做相应的统计操作,包括对行数的统计,对单词数的统计,对字符数的统计,每个功能写在一个单独的函数里面。统计完字符后顺便将数据写入文件。

    五.关键代码分析

    1.命令处理函数

      1 // 对用户输入的命令进行分析
      2 // 传入的用户输入的命令的字符串,中间用空格隔开
      3 // 如果是-开头的,则认为是选项
      4 // 如果检测到-o,就立即读取后面紧跟的输出文件
      5 // 如果不是-开头的,就认为是输入文件
      6 
      7 // 第二个参数是一串文件的头结点
      8 void analyseCommand(char commandStr[], struct Node *Head)
      9 {
     10   // 遍历整个字符串
     11   initFileNode(Head);
     12   struct Node *cur;
     13   cur = Head;
     14   for (int i = 0;; i++)
     15   {
     16     // 读出当前字符
     17     char c = commandStr[i];
     18     // 如果遍历到了,说明字符串结束,则退出函数
     19     if (c == 0)
     20       return;
     21     // 如果c是-,则应该是一个选项
     22     if (c == '-')
     23     {
     24       i++;
     25       // 读取出-后面的字符,并做判断
     26     read:
     27       c = commandStr[i];
     28       // 如果-后面是c,就将_c置为true
     29       if (c == 'c')
     30       {
     31         cur->_c = true;
     32         if (commandStr[++i] != ' ')
     33         {
     34           goto read;
     35         }
     36         continue;
     37       }
     38       // 如果-后面是w,就将_w置为true
     39       else if (c == 'w')
     40       {
     41         cur->_w = true;
     42         if (commandStr[++i] != ' ')
     43         {
     44           goto read;
     45         }
     46         continue;
     47       }
     48       // 如果-后面是l,就将_l置为true
     49       else if (c == 'l')
     50       {
     51         cur->_l = true;
     52         if (commandStr[++i] != ' ')
     53         {
     54           goto read;
     55         }
     56         continue;
     57       }
     58       // 如果-后面是o,则后面紧跟的一个参数一定是filePath
     59       // 首先判断后面是否有文件,如果有,就添加
     60       // 如果没有,就报错
     61       // 此时i的index是在选项上的
     62       else if (c == 'o')
     63       {
     64         i += 2; // 将i移动到
     65         char next = commandStr[i];
     66         if (next == '-' || next == '0')
     67         {
     68           printf("after -o must a para
    ");
     69           exit(-1);
     70         }
     71         char path[100] = ""; // 用来存放输出路径
     72         for (int j = 0;; j++)
     73         {
     74           // 读取出命令中的文件名中的每一个字符
     75           char ch = commandStr[i++];
     76 
     77           // 如果读取到了0,就说明文件名读取结束,就退出
     78           if (ch == ' ')
     79           {
     80             break;
     81           }
     82           path[j] = ch;
     83         }
     84         memset(outFile, 0, sizeof(outFile));
     85         strcpy(outFile, path);
     86       }
     87       else
     88       {
     89         // 如果-后面什么都没有,就判定为错误
     90         printf("after - must a para
    ");
     91         exit(-1);
     92       }
     93     }
     94     else
     95     {
     96       // 如果不是-,则判定为输入文件
     97       // 此时i定位在输入文件的第一个字符上
     98       char path[100] = "";
     99       for (int j = 0;; j++)
    100       {
    101         char ch = commandStr[i++];
    102         if (ch == ' ')
    103         {
    104           break;
    105         }
    106         path[j] = ch;
    107       }
    108       strcpy(cur->inFile, path);
    109       cur->_hasFile = true;
    110       struct Node *fileNode;
    111       fileNode = (struct Node *)malloc(sizeof(struct Node));
    112       initFileNode(fileNode);
    113       cur->next = fileNode;
    114       cur = fileNode;
    115       i--;
    116     }
    117   }
    118   // 检测是否有输入文件
    119   // if (strlen(cur->inFile) == 0)
    120   // {
    121   //   printf("you do not have input file");
    122   //   exit(-1);
    123   // }
    124 }

    代码分析:该函数是这次作业中最重要的一个函数,因此单独拿出来说一下。

    要点说明:

    1.使用for循环遍历整个字符串

    2.遇到-之后就认为是一个选项,就紧接着读取他的后一个字符,如果是有效参数,就记录在当前文件的结构体中,否则报错

    3.如果是-o,则认为后面紧跟着一个输出文件,不做文件名有效性检验,不做权限检查

    4.如果是普通字符开头,则认为是输入文件,不做文件名有效性检查,不做权限检查

    5.根据规则,输出文件应该放在该文件对应参数的后面

    6.遍历完毕之后,就将相关数据都保存在了文件的结构体中,并连接成了链表,返回后可进行后期相关操作。

    六.测试设计

    根据要求,根据如下条件设计测试:

    是否有输入

    是否输入-

    -后是否有参数

    是否统计行数

    是否统计字符数

    是否统计单词数

    是否支持命令连写

    是否支持多文件统计

    是否有-o

    -o后是否跟文件

    根据以上条件,设计了如下批处理文件:

     1 .wc.exe
     2 .wc.exe -
     3 .wc.exe -l
     4 .wc.exe -c
     5 .wc.exe -w
     6 .wc.exe -lc
     7 .wc.exe -lw
     8 .wc.exe -cw
     9 .wc.exe -lcw
    10 .wc.exe -lcw -o
    11 .wc.exe -lcw -o res.txt
    12 .wc.exe -lcw file1.c
    13 .wc.exe -lcw file1.c -o
    14 .wc.exe -lcw file1.c -o res.txt
    15 .wc.exe -lcw file1.c file2.c -o res.txt
    16 .wc.exe -lcw file1.c -lcw file2.c -o res.txt
    17 .wc.exe -lcw file1.c -o -lcw file2.c -o res.txt
    18 PAUSE

    测试结果如下:

    文件输出结果:

    七.参考文献

    《构建之法--现代软件工程》 --邹新 [第三版]

    博客园把我的格式变成了这个样子

    (哇的一声就哭出来了)

  • 相关阅读:
    前端开源项目周报0408
    iOS开源项目周报0406
    安卓开源项目周报0405
    iOS开源项目周报0330
    安卓开源项目周报0329
    前端开源项目周报0328
    vue项目搭建
    微信中h5页面用window.history.go(-1)返回上一页页面不会重新加载问题
    h5移动端页面meta标签
    js中break跳出多层循环
  • 原文地址:https://www.cnblogs.com/guochangyu/p/9695176.html
Copyright © 2011-2022 走看看