WordCount(2)


前排指路
软工项目开发-WordCount(1)
软工项目开发-WordCount(3)
github地址


1. 函数设计实现

实际代码以GitHub中为准。

1.1 基础功能

  • -c :CountChars,字符统计函数,以字符串形式读取文件,遍历字符串中所有字符,判断是否为符合标准的字符,是则字符数加1,否则继续判断下一个字符直至字符串结束。
#region CountChars
		/// <summary>
		/// 字符计数
		/// </summary>
		/// <param name="file">文件路径</param>
		/// <return></return>
		public int CountChars(string file)
		{
			charCnt = 0;
			string text = File.ReadAllText(file);
			foreach (var ch in text)
			{
				if (ch != '\n' && ch != '\r' && ch != '\t')
					charCnt++;
			}
			Console.WriteLine("{0}的字符数:{1}", file, charCnt);
			return charCnt;
		}
#endregion
  • -w:CountWords,单词统计函数,以字符串形式读取文件,将字符串以空格切割为单词,统计切割出的单词数。
#region CountWords
		/// <summary>
		/// 单词计数
		/// </summary>
		/// <param name="file">文件路径</param>
		/// <return></return>
		public int CountWords(string file)
		{
			wordCnt = 0;
			string text = File.ReadAllText(file);
			string[] wordList = text.Split(",.?\n\r".ToArray());
			foreach (var word in wordList)
			{
				if (wordList.Length > 0)
					wordCnt++;
			}
			Console.WriteLine("{0}的单词数: {1}", file, wordCnt);
			return wordCnt;
		}
#endregion
  • -l:CountLines,行数统计函数,这里叙述两个实现思路:
    1. 使用ReadLine函数逐行读取文件内容,每读一行计数加1直至结束。
    2. 以字符串形式读取文件,利用正则表达式提取出字符串中所有回车符\r,其数量加1即为文件行数。

同时,在此处同时进行对于文件内多行注释的统计,利用正则表达式匹配出各个多行注释,并统计其总行数计入commentaryLineCnt中,供之后CountOthers函数进一步进行统计。

#region CountLines
		/// <summary>
		/// 行数计数
		/// </summary>
		/// <param name="file"></param>
		/// <return></return>
		public int CountLines(string file)
		{
			lineCnt = 0;
			commentaryLineCnt = 0;
			string text = File.ReadAllText(file);
			lineCnt = Regex.Matches(text, @"\r").Count + 1;
			//多行注释匹配
			MatchCollection matchCollection = Regex.Matches(text, @"\/\*([^\*]|\*+[^\/\*])*\*+\/");
			foreach (var mc in matchCollection)
			{
				commentaryLineCnt += mc.ToString().Split("\r".ToArray()).Count();
			}
			Console.WriteLine("{0}的行数: {1}", file, lineCnt);
			return lineCnt;
		}
#endregion

1.2 扩展功能

  • -a:CountOthers,代码行/注释行/空行统计函数,对读取的每一行文本进行判断:
    1. 若使用Trim()函数去掉空格后为空,则为空行
    2. 利用StartWith()函数判断,若该行代码以//为开头,或//紧跟在某字符后,将其视为注释行(单行注释统计)
    3. CountLine函数中统计的总行数与空行、代码行相减,即为代码行
#region CountOthers
		/// <summary>
		/// 统计更复杂的数据(代码行/空行/注释行)
		/// </summary>
		/// <param name="file">文件路径</param>
		/// <return></return>
		public string CountOthers(string file)
		{
			codeLineCnt = 0;
			blankLineCnt = 0;
			CountLines(file);
			FileStream fileStream = new FileStream(file, FileMode.Open);
			StreamReader streamReader = new StreamReader(fileStream);
			string line = streamReader.ReadLine();
			while (line != null) //若文件为空,三个值均为0
			{
				if (line.Trim() == "")
				{
					blankLineCnt++;
				}
				else if (line.Trim().IndexOf("//") == 1 || line.Trim().IndexOf("//") == 2)
				{
					//多行注释在CountLine中进行统计
					commentaryLineCnt++;
				}
				line = streamReader.ReadLine();
			}
			codeLineCnt = lineCnt - blankLineCnt - commentaryLineCnt;
			streamReader.Close();
			Console.WriteLine("{0}的空行:{1}, 代码行: {2}, 注释行:{3}", file, blankLineCnt, codeLineCnt, commentaryLineCnt);
			return blankLineCnt.ToString() + "/" + codeLineCnt.ToString() + "/" + commentaryLineCnt.ToString();
		}
#endregion
  • -s:首先创建一个文件列表fileList,用来存放所有获取的文件,对于每一层目录,首先获取当前目录下的所有文件夹,同时,将当前目录下的所有符合条件的文件放入文件列表中,再对其每一个子目录进行同样操作,直至到目录终点。对于文件列表中的每一个文件,根据命令行参数进行-w/-c/-l/-a操作。
/// <summary>
/// 用于存放获取的所有文件
/// </summary>
public static List<FileInfo> fileList = new List<FileInfo>();
#region GetAllFilesInDir
		/// <summary>
		/// 获取所有文件
		/// </summary>
		/// <param name="path">文件夹路径</param>
		/// <param name="ext">要检索的文件扩展名</param>
		/// <returns></returns>
		public static List<FileInfo> GetAllFiles(string path, string ext)
		{
			TraverseDir(path, ext);
			return fileList;
		}
		/// <summary>
		/// 对文件夹进行递归遍历操作获取所有文件
		/// </summary>
		/// <param name="path">文件夹路径</param>
		/// <param name="ext">要检索的文件扩展名</param>
		public static void TraverseDir(string path, string ext)
		{
			if(File.Exists(path))
			{
				Console.WriteLine(path);
				FileInfo file = new FileInfo(path);
				fileList.Add(file);
			}
			else
			{
				string[] dirs = Directory.GetDirectories(path); //获取当前目录下的所有文件夹
				DirectoryInfo directoryInfo = new DirectoryInfo(path);
				FileInfo[] fileInfo = directoryInfo.GetFiles();
				if (fileInfo != null) //获取当前目录下的文件
				{
					foreach (var file in fileInfo)
					{
						if (String.Equals(ext.ToLower(), file.Extension.ToLower()))
						{
							Console.WriteLine(file.FullName);
							fileList.Add(file);
						}
					}
				}
				if (dirs.Length > 0) //递归操作文件夹
				{
					foreach (var dir in dirs)
					{
						TraverseDir(dir, ext);
					}
				}
			}
		}
#endregion

1.3 高级功能(图形界面)

本项目使用WPF作为框架完成UI界面。
当命令行参数包含-x时,调用RunWindow窗口,显示文件选择框 。
C#的OpenFileDialog类可以调用文件对话框,完成文件的选择操作。对于选择的文件,进行-c/-w/-l/-a一系列操作,并通过textBox控件显示在UI界面上这一系列操作在MainWindow.xaml.cs中的button1_Click事件中实现。
界面控件的定义在MainWindow.xaml中实现。

		#region RunWindow
		///<summary>
		///调用窗体函数,同时设置最小化命令行窗口
		///</summary>
		void RunWindow()
		{
			var w = new ConsoleCtrl();
			w.SetWindow(ConsoleCtrl.WindowState.minimize);
			app.InitializeComponent();
			app.Run();
		}
		#endregion

2. 函数调用关系​

启动WordCount.exe后,在main函数中,调用SelectFunction函数,将命令行参数传入,SelectFunction负责对参数种类进行判断,调用不同的函数对文件进行统计。

Main
SelectFunction
CountChars
CountWords
CountLines
CountOthers
RunWindow
GetAllFiles
TraverseDir

3. 单元测试

Visual Studio 2019中,右键想要进行测试的代码段,点击创建单元测试,即可自动生成一个测试类。
创建单元测试
如图,在WordCount下,生成了WordCountTests类,用来对WordCount进行测试。
测试类
在其中的UtilsTests中,编写对Utils的测试。
由于-x需要在图形界面手动操作,因此这里仅对-c/-w/-l/-a/-s进行单元测试,同时,由于-s需与其他参数结合进行测试,故本项目采用的测试用例为:
合法输入:

  1. -c
  2. -w
  3. -l
  4. -a
  5. -s -a
  6. -l -a
  7. -s -w -c

非法输入
8. -q
9. (无功能参数)

由图可见,九个测试用例均运行成功(未知项目为移除的xTest)。
测试用例全部通过
测试覆盖
代码覆盖率仅在Visual Studio Enterprise中可以使用,由于版本限制,本项目无法检测测试代码的代码覆盖率。

发布了3 篇原创文章 · 获赞 0 · 访问量 130
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 技术黑板 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览