WorkCount
软件测试方法和技术第二次作业
1 作业内容
2 WordCount需求说明
2.1 基础功能
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 //将结果输出到指定文件outputFile.txt
注意:
空格,水平制表符,换行符,均算字符。
由空格或逗号分割开的都视为单词,且不做单词的有效性校验,例如:thi#,that视为用逗号隔开的2个单词。
-c, -w, -l参数可以共用同一个输入文件,形如:wc.exe –w –c file.c 。
-o 必须与文件名同时使用,且输出文件必须紧跟在-o参数后面,不允许单独使用-o参数。
2.2 扩展功能
wc.exe -s //递归处理目录下符合条件的文件
wc.exe -a file.c //返回更复杂的数据(代码行 / 空行 / 注释行)
wc.exe -e stopList.txt // 停用词表,统计文件单词总数时,不统计该表中的单词
[file_name]: 文件或目录名,可以处理一般通配符。
其中,
代码行:本行包括多于一个字符的代码。
空 行:本行全部是空格或格式控制字符,如果包括代码,则只有不超过一个可显示的字符,例如“{”。
注释行:本行不是代码行,并且本行包括注释。一个有趣的例子是有些程序员会在单字符后面加注释:
}//注释
在这种情况下,这一行属于注释行。
-e 必须与停用词文件名同时使用,且停用词文件必须紧跟在-e参数后面,不允许单独使用-e参数。
stopList.txt中停用词可以多于1个,单词之间以空格分割,不区分大小写,形如:
while if switch
则while,if,switch作为3个停用词,在单词统计的时候不予考虑。停用词表仅对单词统计产生影响,不影响字符和行数的统计。
2.3 高级功能
wc.exe -x //该参数单独使用,如果命令行有该参数,则程序会显示图形界面,用户可以通过界面选取单个文件,程序就会显示文件的字符数、单词数、行数等全部统计信息。
3 解题过程
解题思路
本作业总体而言比较简单,因此采用面向过程方法就可轻松完成。首先我们知道,Main函数的args[]参数用于储存输入参数。那么命令中的**-o**,**-w**,**-c**等参数的检测就可以交给它来解决。这里为了方便,我们约定- w|c|l|a,-o的输入顺序。也就是说,先指明要操作的文件及命令再指明输出文件
step1 对输入进行检测
出于程序的健壮性考虑,首先要实现的功能应是输入检测。检测内容主要有以下几点
**参数名是否正确**
**参数是否重复输入**
**参数输入顺序是否正确**
**文件名是否符合规范**
**若符合规范,文件是否存在**
参数检测
```
for (i = 0; i < args.Length; i++)
{ //fchar等是初始值为0的int型标志符,每个参数对应一个
if (args[i] == "-c")
{ fChar++; }
else if (args[i] == "-w")
{ fWord++; }
else if (args[i] == "-o")
{ fOutput++; }
else if (args[i] == "-l")
{ fLine++; }
else if(args[i] == "-a")
{ fMore++; }
else if(args[i] == "-s")
{ fRecursion++; }
}
```
对于-o参数除了更改标识符外还要进行赋值操作,其中fileName和ResultFile均为全局变量
if (args[i] == "-o")
{
if (fChar == 0 && fWord == 0 && fLine == 0)
{ //标识符为0说明在-o参数前面并没有- c|w|l|a 参数
Console.WriteLine("错误的命令,若使用-o参数请先在前面使用-c或-w或-i或-l指令");
return false;
}
fileName = args[i - 1]; //-o参数前一个参数必定为操作文件
ResultFile = args[i + 1]; //-o参数后一个参数必定为储存文件
}
参数重复检测
if (fChar > 1 || fWord > 1 || fOutput > 1 || fLine > 1 || fMore > 1)
{ //如果大于一表示输入了至少两个重复参数
Console.WriteLine("输入的参数不能重复,请修改后再输入");
return false;
}
文件规范检测
if (!Regex.IsMatch(fileName, "\\w*\\.(txt|c|docx)"))
{ //检查操作文件格式,利用正则表达式,存储文件的检测同理,将fileName更改为ResulFile即可
Console.WriteLine("Wrong filename,please try again!");
Console.WriteLine("Allowed filename:*.(txt|c|docx)");
return false;
}
文件是否存在
if(!File.Exists(fileName))
{ //不存在该文件
if (!Regex.IsMatch(fileName, "\\*\\.(txt|c|docx)"))
{ //如果文件名格式不为*.c|txt|docx
Console.WriteLine("文件不存在!请重新输入");
return false;
}
}
- 基础功能的实现
对于-c,-w,-l,-a实现的基本思路相同。读取文件内容——>对内容进行处理——>保存需要记录的数据——>关闭文件流
上述四个参数可分别作为四个方法,WordsCount(),CharCount(),LineCount(),MoreCount().其中对于文件的处理均采用StreamReader,保存到字符串Str中
StreamReader sr = new StreamReader(fileName); //打开文件
string str = sr.ReadToEnd(); //读取并保存到str字符串中
四者字符串处理方法不同,字符计数可新建Char[]变量,再将读出的文件内容赋值,char数组的长度即为字符数.
char[] output = str.ToCharArray();
单词计数则利用字符串的split()方法,将读出的内容用','和‘ ’隔开再赋值给string[],string数组的长度即为单词数
string[] Words = str.Split(' ', ',');
行数与单词计数同理,也是利用Split()方法,只是分隔符变成了'\n',string数组的长度即为行数
string[] Lines = str.Split('\n');
代码行/注释行/空行,由于是对每行进行判断,先用string.Split('\n')将文件内容赋值给string数组More[],然后对每一行More[i]进行判断。具体代码如下
for(i = 0;i < More.Length;i++)
{
chr = More[i].Replace(" ", "").Replace("\t","").ToCharArray(); //去掉空格和制表符
if(chr.Length > 1)
{ //字符数大于一,可能是代码行,可能是注释行
if(chr[0] == '}' || chr[0] == '{' && chr[1] == '/' && chr[2] == '/')
{ //去掉空格后如果包括{或}加上//则为注释行
aNote++;
}
else
{ //否则是代码行
aCode++;
}
}
else
{ //去掉空行后字符数小于一,则是空行
aEmpty++;
}
}
其中aNote、aCode、aEmpty为int型计数变量,其他参数也每个对应一个
- 参数-s的实现
首先获取当前目录及其子目录下所有的文件信息,然后找出符合文件名要求的文件进行对应处理,代码如下
/// <summary>
/// 用于递归处理目录下符合条件的文件
/// </summary>
static void Recursion()
{
List<FileInfo> file = GetAllFilesInDirectory(".\\"); //此方法为自定义方法,返回值为FileInfo类型的列表
string[] suffix = fileName.Split('.'); //文件后缀
string pattern = fileName.Replace("*.", "\\w*\\.").Replace(suffix[1], "") + "(" + suffix[1] + ")$"; //将文件名在正则式正确表达出来
foreach(var f in file)
{
if (Regex.IsMatch(f.Name, pattern))
{ //如果文件名符合正则表达式
fileName = f.Name;
//根据参数决定该调用哪些方法
if (fChar > 0)
CharCount(); //字符计数
if (fWord > 0)
WordsCount(); //单词计数
if (fLine > 0)
LinesCount(); //行数计数
if (fMore > 0)
MoreCount(); //代码行、空行、注释行计数
Print(); //将结果输出到屏幕,print为自定义方法
}
}
}
由于题目要求无论参数顺序输出顺序相同,故将输出作为一个方法Print()
static void Print()
{
if (fChar > 0)
Console.WriteLine(fileName + ",字符数:" + aChar.ToString());
if(fWord > 0)
Console.WriteLine(fileName + ",单词数:" + aWord.ToString());
if(fLine > 0)
Console.WriteLine(fileName + ",行数:" + aLine.ToString());
if (fMore > 0)
{
string print = string.Format("代码行/空行/注释行:{0}/{1}/{2}", aCode, aEmpty, aNote);
Console.WriteLine(print);
}
在主界面调用方法即可
static void Main(string[] args)
{
//检查参数,此外-o参数在此方法已解决
if(!Check(args))
{
return;
}
//根据参数决定该调用哪些方法
if (fRecursion > 0)
{
Recursion(); //循环
return;
}
if (fChar > 0)
CharCount(); //字符计数
if (fWord > 0)
WordsCount(); //单词计数
if (fLine > 0)
LinesCount(); //行数计数
if (fMore > 0)
MoreCount(); //代码行、空行、注释行计数
Print(); //将结果输出到屏幕
}
测试
测试文件
测试数据
总结
通过这次作业,我对于文件的操作掌握得更加好,并且对于软件测试也有了更深的了解
WorkCount的更多相关文章
- 第一次作业——WorkCount
项目地址:https://gitee.com/yangfj/wordcount_project 1.软件需求分析: 撰写PSP表格: PSP2.1 PSP阶段 预估耗时 (分钟) 实际耗时 (分钟) ...
- Linux 搭建Hadoop集群 ----workcount案例
在 Linux搭建集群---JDK配置 Linux搭建集群---SSH免密登陆 Linux搭建集群---集群搭建成功 的基础上实现workcount案例 注意 虚拟机三台启动集群(自己亲自搭建) 1. ...
- Flink WorkCount代码
Flink-scala所需依赖 <properties> <flink.version>1.7.0</flink.version> </properties& ...
- ThreadPoolExecutor的runState和workCount变量怎么存储?
在阅读Java线程池ThreadPoolExecutor源码的时候,发现它很巧妙地把线程池状态runState和线程数workCount两个变量存放在了一个int型变量里面. 我们先看一个数值,如下是 ...
- Spark的WorkCount的例子
之前为了搭建scala开发spark的环境花了几天的时间,终于搞定了,具体可以参考:http://www.cnblogs.com/ljy2013/p/4964201.html .下面就是用一个示例 ...
- sparkstreaming+socket workCount 小案例
Consumer代码 import org.apache.spark.SparkConf import org.apache.spark.streaming.StreamingContext impo ...
- 大数据学习day24-------spark07-----1. sortBy是Transformation算子,为什么会触发Action 2. SparkSQL 3. DataFrame的创建 4. DSL风格API语法 5 两种风格(SQL、DSL)计算workcount案例
1. sortBy是Transformation算子,为什么会触发Action sortBy需要对数据进行全局排序,其需要用到RangePartitioner,而在创建RangePartitioner ...
- Oozie_示例
Oozie 官方示例 解压oozie-examples.tar.gz 将examples/上传到HDFS家目录 $ bin/hdfs dfs -put /opt/cdh-5.6.3/oozie-4.0 ...
- 【JUC】JDK1.8源码分析之ThreadPoolExecutor(一)
一.前言 JUC这部分还有线程池这一块没有分析,需要抓紧时间分析,下面开始ThreadPoolExecutor,其是线程池的基础,分析完了这个类会简化之后的分析,线程池可以解决两个不同问题:由于减少了 ...
随机推荐
- 浅析DES原理
对称密码体制 对称密码体制:一种加密系统.其加密密钥和解密密钥是相同的,或者能够从其中之一推知另一个.对称密码体制根据对明文加密方式不同分为分组密码和流密码. 分组密码 分组密码按照一定长度(如64b ...
- Kafka学习(二)
作者:程序员cxuan链接:https://www.zhihu.com/question/53331259/answer/1262483551来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非 ...
- Where和having都是条件筛选关键字,它们有什么分别?
WHERE是在数据分组前进行条件过滤, HAVING子句是在数据分组后进行条件过滤,WHERE子句中不能使用聚合函数,HAVING子句可以使用聚合函数. 需要注意说明:当同时含有where子句.gro ...
- 为什么要使用 rabbitmq?
(1)在分布式系统下具备异步,削峰,负载均衡等一系列高级功能; (2)拥有持久化的机制,进程消息,队列中的信息也可以保存下来. (3)实现消费者和生产者之间的解耦. (4)对于高并发场景下,利用消息队 ...
- Zookeeper 的 java 客户端都有哪些?
java 客户端:zk 自带的 zkclient 及 Apache 开源的 Curator.
- 学习saltstack (七)
一.SaltStack概述 Salt,,一种全新的基础设施管理方式,部署轻松,在几分钟内可运行起来,扩展性好,很容易管理上万台服务器,速度够快,服务器之间秒级通讯. salt底层采用动态的连接总线, ...
- scanf()函数的原理
最近使用scanf发现了自己对scanf函数还是不太了解,主要出现在无意中出现的一个错误: scanf正确的写法是,scanf中以什么格式输入变量,则变量的类型就应该是什么格式,如下面scanf输入到 ...
- CSS实例:翻转图片、滚动图片栏、打开大门
CSS 翻转图片主要用到的技术除了3D翻转和定位 ,还用到了一个属性 backface-visibility:visable|hidden;该属性主要是用来设定元素背面是否可见. 效果图如下: 具体的 ...
- Flex布局在小程序的使用
一篇旧文,上手小程序时做的一些探索 Flex布局是一种十分灵活方便的布局方式,目前主流的现代浏览器基本都实现了对Flex布局的完全支持.而在微信小程序中,IOS端使用的渲染引擎WKWebView和安卓 ...
- vue和mint-ui loadMore 实现上拉加载和下拉刷新
首先安装mint-ui组件库 npm install mint-ui 在main.js中引入mint-ui和样式 import 'mint-ui/lib/style.css' import MintU ...