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计划55
· Estimate· 估计这个任务需要多少时间55
Development开发340635
· Analysis· 需求分析(包括学习新技术)2030
· Design Spec· 生成设计文档3030
· Design Review· 设计复审(和同事审核设计文档)1015
· Coding Standard· 代码规范(为目前的开发制定合适的规范)55
· Design· 具体设计1520
· Coding· 具体编码200400
· Code Review· 代码复审4030
· Test· 测试(自我测试,修改代码,提交修改)2030
Reporting报告6050
· Test Report· 测试报告2015
· Size Measurement· 计算工作量105
· Postmortem & Process improvement Plan· 事后总结,并提出过程改进计划3030
 合计405690

四.解题思路

​ 由于自己对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 -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

 

测试结果如下:

文件输出结果:

七.参考文献

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

 

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

(哇的一声就哭出来了)

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/265932.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

iDempiere = OSGi + ADempiere 一款ERPCRMSCM系统、助力中小企业发展

怀揣着为中小企业量身定做一整套开源软件解决方案的梦想开始了一个网站的搭建。http://osssme.org/ iDempiere OSGi ADempiere 一款ERP&CRM&SCM系统、助力中小企业发展 一句话概括iDempiere是一款基于Compiere/ADempiere的​开源企业级ERP&CRM&SCM系统​&…

字符串 hash 唯一数字_【数字课堂】酒妹带你了解“身份认证技术”

身份认证技术是在计算机网络中确认操作者身份的过程而产生的有效解决方法。计算机网络世界中一切信息包括用户的身份信息都是用一组特定的数据来表示的&#xff0c;计算机只能识别用户的数字身份&#xff0c;所有对用户的授权也是针对用户数字身份的授权。如何保证以数字身份进…

空气中超声衰减

空气中超声衰减是非常厉害的&#xff0c;这导致在空气耦合声换能器的制作或是声传感器的设计是极具挑战的&#xff0c;因此对超声衰减做一个细致的分析是很有必要的。 具体计算根据经验公式如下进行计算 结果如下&#xff1a; Figure 1 超声衰减系数与频率关系图 Figure 2 超声…

java生产者消费者问题代码分析

作者要的是一个生产者生成&#xff0c;接着必须有一个消费者消费&#xff0c;那这不是需要单线程吗&#xff1f;或者使用1个大小的阻塞队列。所以只谈论问题本身&#xff0c;不谈论好不好。 具体代码&#xff1a; Java代码 import java.util.concurrent.locks.Condition; i…

可以ping通 但ssh: connect to host 192.168.0.2 port 22: Connection refused

目录问题描述原因解决问题描述 自己在树莓派端通过SCP指令给电脑上ubuntu传输文件发现提示&#xff1a;ssh: connect to host 192.168.0.2 port 22: Connection refused&#xff0c;并且发现树莓派端是可以ping通ubuntu的。 原因 通过网上查新找到原因&#xff1a; SSH分客…

linux嵌入式贪吃蛇

目标&#xff1a;用游戏手柄控制贪吃蛇 硬件平台&#xff1a;imax6q 版本信息&#xff1a; arm-none-linux-gnueabi-gcc-4.8.3、 qt5.7.1、linux3.0.1 一、交叉编译tslib1.4 由于 imax6q是 armv7-a 构架&#xff0c;所以以后的编译我们都应编译出 armv7 平台的文件 编译参…

2.联邦模式配置---扩容,负载均衡

原理图 两个集群---目的&#xff1a;扩容 HA联邦模式解决了单纯HA模式的性能瓶颈&#xff08;主要指Namenode、ResourceManager&#xff09;&#xff0c;将整个HA集群划分为两个以上的集群&#xff0c;不同的集群之间通过Federation进行连接&#xff0c;使得HA集群拥有了横向扩…

树莓派交叉编译(PS交叉编译链下载安装、配置永久环境变量、带WiringPi库交叉编译、软链接)

目录一、本章概述二、交叉编译工具链的下载安装下载安装交叉编译链临时有效交叉编译链永久有效三、交叉编译的使用对比gcc与armgccPC端交叉编译发送到树莓派运行四、带WiringPi库的交叉编译如何处理复制树莓派上的WiringPi库到主机软硬链接交叉编译一、本章概述 下面将详细介绍…

海量数据处理分析(部分)

2019独角兽企业重金招聘Python工程师标准>>> 1. 海量数据处理分析 原文地址&#xff1a; http://blog.csdn.net/DaiZiLiang/archive/2006/12/06/1432193.aspx 笔者在实际工作中&#xff0c;有幸接触到海量的数据处理问题&#xff0c;对其进行处理是一项艰巨而复…

uboot2015–启动流程分析 imx6q

最近项目原因&#xff0c;要在uboot中增加内核验校和内核损坏修复功能&#xff0c;所以需要回头看看uboot。这次选择了uboot2015来进行分析 uboot是明远睿智提供的。 下载地址 链接&#xff1a;https://pan.baidu.com/s/13SuRii3WTqvFTNIsSS9GAg 密码&#xff1a;65zz 环境&…

树莓派内核开发准备(内核源码获取、启动过程、源码目录树)

目录1.交叉编译工具的安装2.内核源码获取3.嵌入式设备带操作系统的启动过程扫盲4.Linux内核源码树扫盲1.内核源码简介2.Linux内核源代码目录树结构tree指令查看内核源码目录树1.交叉编译工具的安装 参照我之前的笔记 2.内核源码获取 下载哪个版本取决于树莓派的版本&#xf…

柯乐义猜数字游戏

游戏规则&#xff1a;柯乐义请您玩猜数字游戏。后台已经随机生成了一个100到999之间的数字。如果您能在10次之内猜出这个数字&#xff0c;则游戏成功&#xff0c;否则失败。请开始吧。 SilverLight 猜数字游戏&#xff1a;http://keleyi.com/keleyi/phtml/silverlight/ 一次猜数…

fsdisk 分区

芯片主控&#xff1a;imx6q http://lornyin.top/?p545 昨天在做一个linux嵌入式项目时要修改板子的分区&#xff0c;查看了ucl2.xml &#xff08;mfgtool&#xff09;文件后&#xff0c;找到了他的分区脚本 #!/bin/sh# partition size in MB BOOT_ROM_SIZE10# call sfdisk …

树莓派Linux内核源码配置、编译、挂载(boot/kernal/根文件)、开启新内核

目录一、树莓派Linux源码配置(适合树莓派)总体概述配置的三种方式1.照搬厂家的配置&#xff08;使用这种方式&#xff09;2.参考厂家的配置&#xff08;感受一下&#xff09;3.完全自主配置&#xff08;需要一定工作经验&#xff09;二、树莓派Linux内核编译三、树莓派挂载新内…

xshell连接linux出现乱码

今天用Xshell连接linux&#xff0c;查看一个脚本&#xff0c;里面有中文写的注解&#xff0c;出现了乱码&#xff0c;所以记录一下&#xff0c;以便下次用到&#xff0c;也可以帮助遇到同样问题的小伙伴。 以下是乱码的截图&#xff1a; 我们可以照着下面的方式更改编码&#x…

快速排序详解以及java实现

快速排序作为一种高效的排序算法被广泛应用&#xff0c;SUN的JDK中的Arrays.sort 方法用的就是快排。 快排采用了经典的分治思想&#xff08;divide and conquer&#xff09;&#xff1a; Divide&#xff1a;选取一个基元X&#xff08;一般选取数组第一个元素&#xff09;&…

android jni ——Field Method -- Accessing Field

现在我们知道了怎样使用native code访问简单的数据类型和引用参考类型&#xff08;string&#xff0c;array&#xff09;&#xff0c;下面我们来介绍怎样让jni代码去访问java中的成员变量和成员函数&#xff0c;然后可以再jni中回调java中的方法。 ---------------------------…

树状数组的建树 单点修改 单点查询 区间修改 区间查询

单点修改 单点查询 用普通数组就能写出来 单点修改 区间查询 用线段树 树状数组&#xff1b; 区间修改 区间查询 用线段树 树状数组&#xff1b; 区间修改 单点查询 用线段树 树状数组&#xff1b; 建树 #include<bits/stdc.h> using namespace std; …

bert 中文 代码 谷歌_如何用最强模型BERT做NLP迁移学习?

作者 | 台湾大学网红教授李宏毅的三名爱徒来源 | 井森堡&#xff0c;不定期更新机器学习技术文并附上质量佳且可读性高的代码。编辑 | Jane谷歌此前发布的NLP模型BERT&#xff0c;在知乎、Reddit上都引起了轰动。其模型效果极好&#xff0c;BERT论文的作者在论文里做的几个实验…

安装ubuntu20.04(安装vim、gcc、VMtools、中文输入法、汉化、修改IP、无法连网问题)

目录ubuntu安装包获取ubuntu的安装安装网络配置命令ifconfig连接网络(解决ubuntu无法连网问题)如何修改IP地址安装VMtools解决VMware Tools选项灰色VMtools安装安装中文&#xff0c;汉化添加中文输入法调整分辨率安装新版的Vim安装gccubuntu安装包获取 xunlei中直接搜索下载 …