wordCount的c#实现
合作者:201631092112 , 201631092126
码云(gitee)地址:https://gitee.com/ulysses497/wordCount
本次作业地址:https://edu.cnblogs.com/campus/xnsy/Test/homework/2203
(1)互审代码情况
在此次作业中,我们互相写了完整的wordCount代码后,互相进行了代码的审查,发现了很多问题,下列举几个模块审查问题
在合作同学的代码中他将对数据的处理写为一类,读写,操作,写出,写为一类,显得主函数太过冗长,我将代码的读入,操作,主函数归为三类
使得代码更为精简
基本功能概述:
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
拓展功能概述:
wc.exe -a file.c //统计代码行/空行/注释行
wc.exe -s //调用其他-指令
注释:
代码行:本行包括多于一个字符的代码。
空 行:本行全部是空格或格式控制字符,如果包括代码,则只有不超过一个可显示的字符,例如“{”。
注释行:本行不是代码行,并且本行包括注释。一个有趣的例子是有些程序员会在单字符后面加注释:}//注释
在这种情况下,这一行属于注释行。
如下图中的空行/注释行/代码行的计数方法中,我们发现将注释行的if语句嵌套,后对codecount的计数会发生影响
于是进行了改正:
还有很多不便一一赘述,将在下列测试中继续枚举。
项目实现
main函数类:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace WordCount { class Program { static void Main(string[] args) { Console.WriteLine("WordCount"); Console.WriteLine("统计字符数 wc.exe -c file.c "); Console.WriteLine("统计单词总数 wc.exe -w file.c "); Console.WriteLine("统计总行数 wc.exe -l file.c "); Console.WriteLine("统计输出到文件 wc.exe -o file.c "); Console.WriteLine("统计代码行/空行/注释行 wc.exe -a file.c "); Console.WriteLine("调用其他-指令 wc.exe -s "); Console.WriteLine("请输入指令:"); readFile readfile = new readFile(); readfile.Read();//调用读入文件类的Read()方法 Console.WriteLine(); Console.WriteLine("按任意键退出"); Console.ReadKey(); } } } readFile类(对读取的命令进行操作的审查) using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; namespace WordCount { class readFile { public string name = ""; public void Read() { string getcmd = ""; Console.Write("wc.exe "); getcmd = Console.ReadLine(); this.check(getcmd);//调用审查命令函数,进行对cmd的操作是否错误的审查 } string cmd = ""; public void check(string getcmd) //判断输入格式是否正确 { try { this.name = getcmd; string[] file = getcmd.Split(new char[1] { ' ' }, StringSplitOptions.RemoveEmptyEntries);//分割读取的文件名与操作 string filename = ""; bool isopen = true; foreach (string s in file) { if(s.Length>2) { string[] f = s.Split(new char[1] { '.' }, StringSplitOptions.RemoveEmptyEntries); //(f[f.Length - 1] != "c" && f[f.Length - 1] == "t") || (f[f.Length - 1] != "txt") if(f[f.Length-1]!="c") { if(f[f.Length-1]!="txt") { isopen = false; } else { filename = s; } } else { filename = s; } } if (s.Length == 2 && s.Substring(0, 1) == "-")//判断是否为操作命令 { cmd = cmd + s; if (s != "-c" && s != "-w" && s != "-l" && s != "-a"&&s !="-s"&&s!="-o")//处理操作错误 { isopen = false; } if (isopen == false) { Console.WriteLine("----------------------------------------------------------"); Console.WriteLine(" 请输入正确的文件名或您的操作有误 "); Console.WriteLine("----------------------------------------------------------"); this.Read(); break; } } if (s.Length < 2)//处理操作错误 { isopen = false; Console.WriteLine("----------------------------------------------------------"); Console.WriteLine(" 请输入正确的文件名或您的操作有误 "); Console.WriteLine("----------------------------------------------------------"); this.Read(); break; } } if (isopen == true&&cmd!="") { if (cmd.Contains("-s") == false) { this.openFilename(filename); } } else { Console.WriteLine("----------------------------------------------------------"); Console.WriteLine(" 请输入正确的文件名或您的操作有误 "); Console.WriteLine("----------------------------------------------------------"); this.Read(); } if(cmd.Contains("-s")) { handleFile hdfile = new handleFile(); hdfile.checkCmd(cmd); } } catch (Exception e) { Console.WriteLine(e); Console.WriteLine("----------------------------------------------------------"); Console.WriteLine(" 请输入正确的文件名或您的操作有误 "); Console.WriteLine("----------------------------------------------------------"); this.Read(); } } public void openFilename(string name)//打开文件操作 { FileStream fs = new FileStream(@name, FileMode.Open); StreamReader sr = new StreamReader(fs); string allStr = sr.ReadToEnd(); sr.Close(); fs.Close(); handleFile hdfile = new handleFile();//调用操作文件类 hdfile.allstr = allStr; hdfile.cmd = cmd; hdfile.name = name; hdfile.checkCmd(cmd); } } }
handleFile类(处理文件类)
using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; namespace WordCount { class handleFile//处理文件 { public string name = ""; public string allstr = ""; public string cmd = ""; public bool isout; public void checkCmd(string cmdstr) //检查指令 { if(cmdstr.Contains("-o"))//是否进行输出到outfile.txt的操作 { this.isout = true; } else { this.isout = false; } if (cmdstr.Contains("-s")) { cmdstr = cmdstr.Replace("-s", ""); this.handleS(cmdstr); } else { for (int i = 0; i < cmdstr.Length; i++)//判断是什么命令 { if (cmdstr[i] == '-') { if (cmdstr[i + 1] == 'c') { this.handleC(); } else if (cmdstr[i + 1] == 'w') { this.handleW(); } else if (cmdstr[i + 1] == 'l') { this.handleL(); } else if (cmdstr[i + 1] == 'a') { this.handleA(); } } } } } public void handleC()//调用正则表达式对字符数的统计进行审查 { var cStr = this.allstr; Regex re = new Regex(@"(\r\n)|(\S)|(\u0020)|(\u3000)"); //换行和回车符不是同一个 int count = re.Matches(this.allstr).Count; Console.WriteLine(); Console.WriteLine(this.name+" "+ "字符数:"+count); this.rstFile(Convert.ToString(this.name + " " + "字符数:" + count)); this.outputFile(Convert.ToString(this.name + " " + "字符数:" + count), this.isout); } public void handleW() { string wStr = this.allstr; string[] sArray = wStr.Split(new char[3] { ' ', ',','\r' }, StringSplitOptions.RemoveEmptyEntries); //" "与","作为分割符 int count = 0; foreach (string s in sArray)//遍历统计单词数量 { count++; } Console.WriteLine(); Console.WriteLine(this.name + " " + "单词数:"+count); this.rstFile(Convert.ToString(this.name + " " + "单词数:" + count)); this.outputFile(Convert.ToString(this.name + " " + "单词数:" + count), this.isout); } public void handleL() { FileStream fs = new FileStream(@name, FileMode.Open); StreamReader sr = new StreamReader(fs); int lines = 0; while (sr.ReadLine() != null)//遍历统计行数(包含空行) { lines++; } sr.Close(); fs.Close(); Console.WriteLine(this.name + " " + "行数:"+lines); this.rstFile(Convert.ToString(this.name + " " + "行数:" + lines)); this.outputFile(Convert.ToString(this.name + " " + "行数:" + lines), this.isout); } public void handleA()//空行/注释行/代码行的计数 { FileStream fs = new FileStream(@name, FileMode.Open); StreamReader sr = new StreamReader(fs); string lines = ""; int nullcount = 0; int notedcount = 0; int codecount = 0; while ((lines =sr.ReadLine()) != null) { lines = lines.Trim(' ');//每一行去掉两头空白字符 lines = lines.Trim('\t');//每一行去掉两头TAB字符 if (lines == "" || lines.Length <= 1) { nullcount++;//空行计数加一 } else if (lines.Length > 2 && (lines.Substring(0, 2) == "//" || lines.Substring(1, 2) == "//")) { notedcount++;//注释行计数加一 } else if (lines.Length == 2 && (lines.Substring(0, 2) == "//")) { notedcount++; //注释行计数加一 } else { codecount++;//代码行计数加一 } } sr.Close(); fs.Close(); string outstr = this.name + " " + "空行/注释行/代码行:" + nullcount.ToString() + "/" + notedcount.ToString() + "/" + codecount.ToString(); Console.WriteLine(); Console.WriteLine(this.name + " "+"空行/注释行/代码行:" +@"{0}/{1}/{2}", nullcount, notedcount, codecount); this.rstFile(outstr); this.outputFile(outstr, this.isout); } public void handleS(string cmd)//-s命令调用其它命令函数 { string rootPath = Directory.GetCurrentDirectory(); string[] files = Directory.GetFiles(rootPath, "*.c"); foreach (string file in files) { FileStream fs = new FileStream(@file, FileMode.Open); StreamReader sr = new StreamReader(fs); this.allstr = sr.ReadToEnd(); sr.Close(); fs.Close(); this.name = file; this.checkCmd(cmd); } } public void rstFile(string str)//输出函数 { string filePath = Directory.GetCurrentDirectory(); StreamWriter sw = new StreamWriter(@filePath+"//"+"result.txt", true, Encoding.UTF8); sw.WriteLine(str); sw.Close(); } public void outputFile(string str, bool isout)//-0命令,输出到output.txt { if (isout) { string filePath = Directory.GetCurrentDirectory(); StreamWriter sw = new StreamWriter(@filePath + "//" + "output.txt", true, Encoding.UTF8); sw.WriteLine(str); sw.Close(); } } } }
性能测试
测试工具:VS2013的性能测试工具
原来对字符数等命令统计使用的是for循环遍历的方法
代码如下
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.IO; namespace WordCount { class DataProcess { //打开.c文件并将内容以字符串形式读取出来 public string openFile(string fstr) { FileStream fs = new FileStream(fstr, FileMode.Open); byte[] array = new byte[fs.Length]; fs.Read(array,0, array.Length); fs.Close(); string str = Encoding.UTF8.GetString(array); return str; } //统计字符数 public int cProcess(string fstr) { string str = openFile(fstr); int charCount = 0; charCount = str.Length; foreach(char c in str) { if(c=='\n') { charCount--; } } StreamWriter sw = new StreamWriter("result.txt", true); sw.WriteLine(fstr + " 字符数: " + Convert.ToString(charCount)); sw.Close(); return charCount; } //统计行数 public int lProcess(string fstr) { string str = openFile(fstr); int lineCount = 1; foreach (char l in str) { if (l == '\n') { lineCount++; } } StreamWriter sw = new StreamWriter("result.txt", true); sw.WriteLine(fstr + " 行数: " + Convert.ToString(lineCount)); sw.Close(); return lineCount; } //统计单词书 public int wProcess(string lstr) { string str = openFile(lstr); int count = 1; bool isBlank = true; foreach(char s in str) { if(s!=' ' && s!= '\n' &&s!=','&& isBlank==true) { count++; isBlank = false; } else if((s==' '||s=='\n'||s==',')&&isBlank==false) { isBlank = true; } } StreamWriter sw = new StreamWriter("result.txt", true); sw.WriteLine(lstr + " 单词数:" + Convert.ToString(count - 1)); sw.Close(); return count - 1; } //统计代码行/空行/注释行 public string aProcess(string astr) { FileStream fs = new FileStream(astr, FileMode.Open); StreamReader sr = new StreamReader(fs); string lines = ""; int codeLineCount = 0; int nullLineCount = 0; int noteLineCount = 0; while ((lines = sr.ReadLine()) != null) { lines = lines.Trim(' '); lines = lines.Trim('\t'); if (lines == "" || lines.Length <= 1) { nullLineCount++; } else if (lines.Length > 2 && lines.Substring(0, 2) == "//" || lines.Substring(1, 2) == "//") { noteLineCount++; } else if(lines.Length==2 && lines.Substring(0, 2) == "//") { noteLineCount++; } else { codeLineCount++; } } string complexLineCount = Convert.ToString(codeLineCount) + "/"+Convert.ToString(nullLineCount) +"/"+ Convert.ToString(noteLineCount); StreamWriter sw = new StreamWriter("result.txt", true); sw.WriteLine(astr + " 代码行/空行/注释行:" + Convert.ToString(codeLineCount)+"/"+Convert.ToString(nullLineCount)+"/"+Convert.ToString(noteLineCount)); sw.Close(); return complexLineCount; } //将统计的数据存入指定文件 public string oProcess(string oFile) { System.IO.File.WriteAllText(oFile, string.Empty); string str = openFile("result.txt"); StreamWriter sw = new StreamWriter(oFile, true); sw.WriteLine(str); sw.Close(); return oFile; } } }
对其进行性能测试
后改用正则表达式的方法,并在对其他代码进行优化后再进行性能测试
代码如下:
using
System;
using
System.Collections.Generic;
using
System.IO;
using
System.Linq;
using
System.Text;
using
System.Text.RegularExpressions;
using
System.Threading.Tasks;
namespace
WordCount
{
class
handleFile
//处理文件
{
public
string
name =
""
;
public
string
allstr =
""
;
public
string
cmd =
""
;
public
bool
isout;
public
void
checkCmd(
string
cmdstr)
//检查指令
{
if
(cmdstr.Contains(
"-o"
))
//是否进行输出到outfile.txt的操作
{
this
.isout =
true
;
}
else
{
this
.isout =
false
;
}
if
(cmdstr.Contains(
"-s"
))
{
cmdstr = cmdstr.Replace(
"-s"
,
""
);
this
.handleS(cmdstr);
}
else
{
for
(
int
i = 0; i < cmdstr.Length; i++)
//判断是什么命令
{
if
(cmdstr[i] ==
'-'
)
{
if
(cmdstr[i + 1] ==
'c'
)
{
this
.handleC();
}
else
if
(cmdstr[i + 1] ==
'w'
)
{
this
.handleW();
}
else
if
(cmdstr[i + 1] ==
'l'
)
{
this
.handleL();
}
else
if
(cmdstr[i + 1] ==
'a'
)
{
this
.handleA();
}
}
}
}
}
public
void
handleC()
//调用正则表达式对字符数的统计进行审查
{
var
cStr =
this
.allstr;
Regex re =
new
Regex(
@"(\r\n)|(\S)|(\u0020)|(\u3000)"
);
//换行和回车符不是同一个
int
count = re.Matches(
this
.allstr).Count;
Console.WriteLine();
Console.WriteLine(
this
.name +
" "
+
"字符数:"
+ count);
this
.rstFile(Convert.ToString(
this
.name +
" "
+
"字符数:"
+ count));
this
.outputFile(Convert.ToString(
this
.name +
" "
+
"字符数:"
+ count),
this
.isout);
}
public
void
handleW()
{
string
wStr =
this
.allstr;
string
[] sArray = wStr.Split(
new
char
[3] {
' '
,
','
,
'\r'
}, StringSplitOptions.RemoveEmptyEntries);
//" "与","作为分割符
int
count = 0;
foreach
(
string
s
in
sArray)
//遍历统计单词数量
{
count++;
}
Console.WriteLine();
Console.WriteLine(
this
.name +
" "
+
"单词数:"
+ count);
this
.rstFile(Convert.ToString(
this
.name +
" "
+
"单词数:"
+ count));
this
.outputFile(Convert.ToString(
this
.name +
" "
+
"单词数:"
+ count),
this
.isout);
}
public
void
handleL()
{
FileStream fs =
new
FileStream(@name, FileMode.Open);
StreamReader sr =
new
StreamReader(fs);
int
lines = 0;
while
(sr.ReadLine() !=
null
)
//遍历统计行数(包含空行)
{
lines++;
}
sr.Close();
fs.Close();
Console.WriteLine(
this
.name +
" "
+
"行数:"
+ lines);
this
.rstFile(Convert.ToString(
this
.name +
" "
+
"行数:"
+ lines));
this
.outputFile(Convert.ToString(
this
.name +
" "
+
"行数:"
+ lines),
this
.isout);
}
public
void
handleA()
//空行/注释行/代码行的计数
{
FileStream fs =
new
FileStream(@name, FileMode.Open);
StreamReader sr =
new
StreamReader(fs);
string
lines =
""
;
int
nullcount = 0;
int
notedcount = 0;
int
codecount = 0;
while
((lines = sr.ReadLine()) !=
null
)
{
lines = lines.Trim(
' '
);
//每一行去掉两头空白字符
lines = lines.Trim(
'\t'
);
//每一行去掉两头TAB字符
if
(lines ==
""
|| lines.Length <= 1)
{
nullcount++;
//空行计数加一
}
else
if
(lines.Length > 2 && (lines.Substring(0, 2) ==
"//"
|| lines.Substring(1, 2) ==
"//"
))
{
notedcount++;
//注释行计数加一
}
else
if
(lines.Length == 2 && (lines.Substring(0, 2) ==
"//"
))
{
notedcount++;
//注释行计数加一
}
else
{
codecount++;
//代码行计数加一
}
}
sr.Close();
fs.Close();
string
outstr =
this
.name +
" "
+
"空行/注释行/代码行:"
+ nullcount.ToString() +
"/"
+ notedcount.ToString() +
"/"
+ codecount.ToString();
Console.WriteLine();
Console.WriteLine(
this
.name +
" "
+
"空行/注释行/代码行:"
+
@"{0}/{1}/{2}"
, nullcount, notedcount, codecount);
this
.rstFile(outstr);
this
.outputFile(outstr,
this
.isout);
}
public
void
handleS(
string
cmd)
//-s命令调用其它命令函数
{
string
rootPath = Directory.GetCurrentDirectory();
string
[] files = Directory.GetFiles(rootPath,
"*.txt"
);
foreach
(
string
file
in
files)
{
FileStream fs =
new
FileStream(@file, FileMode.Open);
StreamReader sr =
new
StreamReader(fs);
this
.allstr = sr.ReadToEnd();
sr.Close();
fs.Close();
this
.name = file;
this
.checkCmd(cmd);
}
}
public
void
rstFile(
string
str)
//输出函数
{
string
filePath = Directory.GetCurrentDirectory();
StreamWriter sw =
new
StreamWriter(@filePath +
"//"
+
"result.txt"
,
true
, Encoding.UTF8);
sw.WriteLine(str);
sw.Close();
}
public
void
outputFile(
string
str,
bool
isout)
//-0
{
if
(isout)
{
string
filePath = Directory.GetCurrentDirectory();
StreamWriter sw =
new
StreamWriter(@filePath +
"//"
+
"output.txt"
,
true
, Encoding.UTF8);
sw.WriteLine(str);
sw.Close();
}
}
}
}
可以发现性能有了明显提升
测试用例及结果:
用例1:
结果:
用例2:
结果:
错误用例示范:
总结与收获
黄乙轩:在这次wordCount的设计与测试中,我对于软件测试有了较为详细的认知,在学习过程中,我逐渐掌握了c#文件的读写操作,正则表达式的基本应用,控制台命令的实现,
读写命令的逻辑判断,异常或错误的处理方式的运用,同时掌握了白盒测试,静态测试,性能测试的基本操作,在以后的学习,开发过程中,我也会将在这
次开发过程中学到的东西运用到实际中。
杨柳:这次进行的WordCount的作业中,一开始看题目,完全没有头绪,在网上查阅了相关资料后,逐渐理清楚了题目要求的思路逻辑。由于一直接触的是C#窗体应用设计,很久没有接触C#控制台设计了,导致很多操作都比较生疏,因此花费了较多时间去熟悉。在此次作业中,重点是对文件的读写操作,以及对字符串的遍历操作。在有些函数中,我使用了较基础的方法,效率较低,当看见了合作同学所使用的正则表达式后,我也去了解了一下正则表达式。对整体代码进行编写完成后,之后的软件测试则是本课程的核心。在本次测试中,我学习了解到了静态测试,白盒测试,性能测试。对软件测试这门课程有了更深刻的了解。在今后的项目开发学习过程中,我会学以致用,将学习到的学习充分利用到实际情况当中去。