博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Word Count作业
阅读量:4308 次
发布时间:2019-06-06

本文共 5662 字,大约阅读时间需要 18 分钟。

Word Count作业

一.个人Gitee地址:

二.项目简介

该项目主要是模拟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.1 PSP阶段 预估耗时(分钟) 实际耗时(分钟)
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     // 如果遍历到了\0,说明字符串结束,则退出函数 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\n"); 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\n"); 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 -lcw10 .\wc.exe -lcw -o11 .\wc.exe -lcw -o res.txt12 .\wc.exe -lcw file1.c13 .\wc.exe -lcw file1.c -o14 .\wc.exe -lcw file1.c -o res.txt15 .\wc.exe -lcw file1.c file2.c -o res.txt16 .\wc.exe -lcw file1.c -lcw file2.c -o res.txt17 .\wc.exe -lcw file1.c -o -lcw file2.c -o res.txt18 PAUSE

 

测试结果如下:

文件输出结果:

七.参考文献

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

 

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

(哇的一声就哭出来了)

转载于:https://www.cnblogs.com/guochangyu/p/9695176.html

你可能感兴趣的文章
Linux(SUSE 12)安装Tomcat
查看>>
Linux(SUSE 12)安装jboss4并实现远程访问
查看>>
Neutron在给虚拟机分配网络时,底层是如何实现的?
查看>>
netfilter/iptables全攻略
查看>>
Overlay之VXLAN架构
查看>>
Eclipse : An error occurred while filtering resources(Maven错误提示)
查看>>
在eclipse上用tomcat部署项目404解决方案
查看>>
web.xml 配置中classpath: 与classpath*:的区别
查看>>
suse如何修改ssh端口为2222?
查看>>
详细理解“>/dev/null 2>&1”
查看>>
suse如何创建定时任务?
查看>>
suse搭建ftp服务器方法
查看>>
centos虚拟机设置共享文件夹并通过我的电脑访问[增加smbd端口修改]
查看>>
文件拷贝(IFileOperation::CopyItem)
查看>>
MapReduce的 Speculative Execution机制
查看>>
大数据学习之路------借助HDP SANDBOX开始学习
查看>>
Hadoop基础学习:基于Hortonworks HDP
查看>>
为什么linux安装程序 都要放到/usr/local目录下
查看>>
Hive安装前扫盲之Derby和Metastore
查看>>
永久修改PATH环境变量的几种办法
查看>>