github项目地址:https://github.com/insomniali/wc

  • 基本功能

    • wc.exe -c file     统计文件file的字符数  【实现】
    • wc.exe -w file    统计文件file的词的数目  【实现】
    • wc.exe -l file      统计文件file的行数  【实现】
  • 扩展功能
    •     wc.exe -d file      递归显示目录下符合条件的文件  【实现】
    • wc.exe -s file       递归统计目录下符合条件的文件的总字符,词和行数  【实现】
    • wc.exe -a file       统计文件file的空白行,注释行,代码行  【实现】
  • 高级功能
    •      wc.exe -x            图形化界面  【未实现】

设计思路

根据需求,程序主要功能可分为两部分,一是接收输入指令并解析,二是对文件执行指令所对照的操作。通过程序内置参数,再调用相应类方法即可满足需求。

字符统计函数:

定义:除转义字符,数字及字母外所有字符

方法:通过getline()获取一行数据,再由字符的ASCII码来判断

单词统计函数:

定义:“a-z”,"A-Z"组成的单个字母或多个连续字母组成的单词

方法:通过getline()获取一行数据,再由字符的ASCII码来判断,在统计完第一个字母后置continuectrl为真,直到统计到第一个不符合定义的字符

行数统计函数

定义:通过getline()判断,不为空则为有效行

方法:grtline()

空白,注释,代码行数统计函数

定义:

空白行:字符串长度为0或长度为1,字符为(;,{,})之一

注释行:以“{//”,“}//”,“;//”,“//”为字符串开头的行

代码行:除空白行,注释行以外所有行

方法:

空白行:用string.length()统计字符串长度,符合定义即为空白行

注释行:获取字符串前三位字符,根据结果是否符合定义判断

代码行:总行数减去空白行数及注释行数

架构图

设计了一个WCclass类,类成员变量是int类型的各种统计数据,类成员方法则是统计各种数据

代码说明

主函数main()

int main(int argc ,char* argv[]) {
string filepath = "C:\\Users\\L\\Desktop\\软件工程\\test"; //测试路径
string filename;
string temp;
string operateword;
string paramater=argv[];
WCclass * test=new WCclass();
for (int i = ; i < argc + ; i++)
{
temp = filepath;
filename = argv[i];
filename = temp + "\\" + filename;
test->fileoperate(filename, paramater);
}
detele test;
return ;
}

指令解析与文件操作函数()

void WCclass::fileoperate(string filename, string paramater)
{
ifstream fin(filename.c_str()); //获取文件名,打开输入流 char ch; //每次判断一个字符
string str; //保存行数据
char **strs; //保存字符串str以“ ”分割的字符串
//可输入参数类型
string paramater1 = "-c";
string paramater2 = "-w";
string paramater3 = "-l";
string paramater4 = "-d";
string paramater5 = "-s";
string paramater6 = "-a"; strs = (char**)malloc(sizeof(char) * ); while (getline(fin, str))
{
int strcount = ;
rowcount(); if ((str.length() == ) || ((str.length() == )&& (str[strcount] == (char)"{")) || ((str.length() == ) && (str[strcount] == (char)"}")))
{
emptyrowcount();
continue;
} strs[strcount] = strtok((char*)str.c_str(), " "); while (strs[strcount] != NULL)
{
strcount++;
strs[strcount] = strtok(NULL, " ");
} for (int i = ; i < strcount; i++)
{
string temp = strs[i];
int continuectrl = ;//控制单词连续
int dqmoff = ;//是否是;,{,}
int flag = ;////是否相邻
for (int j = ; j < temp.length(); j++)
{
ch = temp[j];
if ((ch >= && ch <= ) || (ch >= && ch <= ) || (ch >= && ch <= ) || (ch >= && ch <= ))
{
charcount();
continuectrl = ;
//注释行//的情况
if (ch == )
{
if (j == )
{
flag = ;
}
else if (j == )
{
if (flag == )
{
flag = ;
noterowcount();
}
}
}
//注释行({//,}//,;//)的情况
if ((ch == ) || (ch == ) || (ch == ))
{
if (j == ) {
dqmoff = ;
continue;
}
}
if (dqmoff == )
{
if (ch == )
{
if (flag == )
{
flag = ;
noterowcount();
}
else flag = ;
}
else
{
dqmoff = ;
}
} }
else if ((ch >= && ch <= ) || (ch >= && ch <= ))
{
if (continuectrl == )continue;
continuectrl = ;
wordcount();
}
else if (ch >= ''&&ch <= '')
{
digitcount();
}
else
{
cnwordcount();
}
}
}
}
if (paramater == paramater1)std::cout << "字符数为:" << charnums + cnwordnums / << endl;
else if (paramater == paramater2)std::cout << "单词数为:" << wordnums << endl;
else if (paramater == paramater3)std::cout << "行数为:" << rownums << endl;
else if (paramater == paramater4)listFiles(filename.c_str());
else if (paramater == paramater5)
{
filegroup = (string*)malloc(sizeof(string) * );
filegroup=listFiles(filename.c_str(), filegroup); //获取递归处理文件的文件名数组
for (int i = ; filegroup[i].length() != ; i++) {
std::cout << filegroup[i] << endl;
fileoperate(filegroup[i], paramater1);
fileoperate(filegroup[i], paramater2);
fileoperate(filegroup[i], paramater3);
}
std::cout << endl;
std::cout << "总字符数为:" << charnums + cnwordnums / << endl;
std::cout << "总单词数为:" << wordnums << endl;
std::cout << "总行数为:" << rownums << endl;
}
else if (paramater == paramater6)
{
std::cout << "空行数为:" << emptyrow << endl;
std::cout << "注释行数为:" << noterow << endl;
std::cout << "代码行数为:" << rownums-emptyrow-noterow << endl;
} fin.clear();
fin.close();
free(strs);
}

递归处理函数ListFiles()

void listFiles(const char * dir)
{
char dirNew[];
strcpy(dirNew, dir); intptr_t handle; //intptr_t是为了跨平台,其长度总是所在平台的位数,用来存放地址。
_finddata_t FileInfo; // _finddata_t 是用来存储文件各种信息的结构体。 handle = _findfirst(dirNew, &FileInfo); //第一个参数为文件名,可以用"*.*"来查找所有文件,也可以用"*.cpp"来查找.cpp文件。第二个参数是_finddata_t结构体指针。若查找成功,返回文件句柄,若失败,返回-1。
if (handle == -) // 检查是否成功
return; do
{
if (FileInfo.attrib & _A_SUBDIR) //如果文件是目录
{
if (strcmp(FileInfo.name, ".") == || strcmp(FileInfo.name, "..") == ) //如果文件名和当前目录和父目录相同则跳过,否则会只输出当前目录
continue; std::cout << FileInfo.name << "\t<目录>\n"; // 在目录后面加上"\\"和搜索到的目录名进行下一次搜索
strcpy(dirNew, dir);
strcat(dirNew, "\\");
strcat(dirNew, FileInfo.name); listFiles(dirNew);
}
else
std::cout << FileInfo.name << "\t" << "\n";
} while (_findnext(handle, &FileInfo) == ); //_findnext第一个参数为文件句柄,第二个参数同样为_finddata_t结构体指针。若查找成功,返回0,失败返回 - 1。 _findclose(handle); // 关闭搜索句柄
} std::string* listFiles(const char * dir,std::string* str)
{
char dirNew[];
strcpy(dirNew, dir);
int filenum = ;
std::string* temp = new std::string[];
int partcount = ;
std::string filepath;
char**filepathpart;
filepathpart = (char**)malloc(sizeof(char) * );
std::string filepathtemp = dir; intptr_t handle; //intptr_t是为了跨平台,其长度总是所在平台的位数,用来存放地址。
_finddata_t FileInfo; // _finddata_t 是用来存储文件各种信息的结构体。 handle = _findfirst(dirNew, &FileInfo); //第一个参数为文件名,可以用"*.*"来查找所有文件,也可以用"*.cpp"来查找.cpp文件。第二个参数是_finddata_t结构体指针。若查找成功,返回文件句柄,若失败,返回-1。
if (handle == -) // 检查是否成功
return nullptr; filepathpart[partcount] = strtok((char*)filepathtemp.c_str(), "\\"); while (filepathpart[partcount] != NULL)
{
partcount++;
filepathpart[partcount] = strtok(NULL, "\\");
} for (int i = ; i < partcount - ; i++) {
filepath += filepathpart[i] ;
filepath += "\\";
} do
{
if (FileInfo.attrib & _A_SUBDIR) //如果文件是目录
{
if (strcmp(FileInfo.name, ".") == || strcmp(FileInfo.name, "..") == ) //如果文件名和当前目录和父目录相同则跳过,否则会只输出当前目录
continue; std::cout << FileInfo.name << "\t<目录>\n"; // 在目录后面加上"\\"和搜索到的目录名进行下一次搜索
strcpy(dirNew, dir);
strcat(dirNew, "\\");
strcat(dirNew, FileInfo.name); listFiles(dirNew); }
else {
temp[filenum] = filepath;
temp[filenum] += FileInfo.name;
filenum++;
std::cout << FileInfo.name << "\t" << " \n";
}
} while (_findnext(handle, &FileInfo) == ); //_findnext第一个参数为文件句柄,第二个参数同样为_finddata_t结构体指针。若查找成功,返回0,失败返回 - 1。 _findclose(handle); // 关闭搜索句柄
return temp;
}

测试运行

测试-c,-w,-l,-a

测试文件:1.cpp

测试结果:

C:\Users\L\Desktop\软件工程\wc\Release>wc.exe -c 1.cpp
字符数为:30
C:\Users\L\Desktop\软件工程\wc\Release>wc.exe -w 1.cpp
单词数为:10
C:\Users\L\Desktop\软件工程\wc\Release>wc.exe -l 1.cpp
行数为:13
C:\Users\L\Desktop\软件工程\wc\Release>wc.exe -a 1.cpp
空行数为:1
注释行数为:3
代码行数为:9
测试-d
测试结果:
C:\Users\L\Desktop\软件工程\wc\Release>wc.exe -d *.*
1.cpp
113.cpp
13.cpp
2.cpp
555     <目录>
main.cpp
wcclass.h
测试-s
测试结果:
1.cpp
113.cpp
13.cpp
2.cpp
main.cpp
C:\Users\L\Desktop\软件工程\test\1.cpp
字符数为:30
单词数为:20
行数为:39
C:\Users\L\Desktop\软件工程\test\113.cpp
字符数为:104
单词数为:52
行数为:75
C:\Users\L\Desktop\软件工程\test\13.cpp
字符数为:146
单词数为:85
行数为:111
C:\Users\L\Desktop\软件工程\test\2.cpp
字符数为:185
单词数为:114
行数为:141
C:\Users\L\Desktop\软件工程\test\main.cpp
字符数为:588
单词数为:581
行数为:417
 
 
总字符数为:1351
总单词数为:810
总行数为:417
 
代码覆盖率:100%
PSP

PSP2.1

Personal Software Process Stages

预估耗时(分钟)

实际耗时(分钟)

Planning

计划

30

45

· Estimate

· 估计这个任务需要多少时间

10

10

Development

开发

100

300

· Analysis

· 需求分析 (包括学习新技术)

60

30

· Design Spec

· 生成设计文档

20

20

· Design Review

· 设计复审 (和同事审核设计文档)

20

100

· Coding Standard

· 代码规范 (为目前的开发制定合适的规范)

20

10

· Design

· 具体设计

10

10

· Coding

· 具体编码

10

10

· Code Review

· 代码复审

10

100

· Test

· 测试(自我测试,修改代码,提交修改)

30

200

Reporting

报告

10

30

· Test Report

· 测试报告

10

30

· Size Measurement

· 计算工作量

10

10

· Postmortem & Process Improvement Plan

· 事后总结, 并提出过程改进计划

30

20

合计

 

380

925

 项目总结
              这次项目让我感受最大的在于测试方面,之前写代码没有作过多的测试。这次学习到单元测试,代码覆盖率等方法和概念,可以应用到以后的程序开发中。其次,psp表也是一个新的概念,一开始估计时间都比较少,过于乐观,直到开发和测试阶段,很多没有想到的小问题让我卡住了很长一段时间,以至于实际时间比估计时间翻了三倍。最后是让我学会了先写好大致框架再实现,没有出现以前的边写边改,最好代码很紊乱的问题。我相信一个好的程序员是在开发中成长的,这次项目为我的开发之路开了个好头。

C++实现wc.exe程序的更多相关文章

  1. wc.exe程序

    1.gitHub地址:https://github.com/loveYuJun/wc.exe.git 2.PSP表格 psp2.1 Personal Software Process Stages 预 ...

  2. wc.exe指令(C++)

    https://github.com/kielingpao/wc 项目相关要求 wc.exe 是一个常见的工具,它能统计文本文件的字符数.单词数和行数.这个项目要求写一个命令行程序,模仿已有wc.ex ...

  3. 个人项目(WC.exe)(java)(基于图形界面)

    一.Github项目地址:https://github.com/Leungdc/ENhomework 二.PSP: PSP2.1 Personal Software Process Stages 预估 ...

  4. WC.exe【C】

    gitee传送门!!!(电脑打不开github,多次尝试未果,决定先用gitee存着先) 项目要求 wc.exe 是一个常见的工具,它能统计文本文件的字符数.单词数和行数.这个项目要求写一个命令行程序 ...

  5. 小白のjava实现wc.exe功能

    GitHub地址 项目完成情况 基本功能列表(已实现) wc.exe -c file.c     //返回文件 file.c 的字符数 wc.exe -w file.c    //返回文件 file. ...

  6. 模仿WC.exe的功能实现--node.js

    Github项目地址:https://github.com/102derLinmenmin/myWc WC 项目要求 wc.exe 是一个常见的工具,它能统计文本文件的字符数.单词数和行数.这个项目要 ...

  7. 软工作业1—java实现wc.exe

    github项目地址 https://github.com/liyizhu/wc.exe WC 项目要求 基本功能列表: wc.exe -c file.c     //返回文件 file.c 的字符数 ...

  8. 用c语言基本实现wc.exe功能

    网址:https://github.com/3216005214/wc.exe wc项目要求 wc.exe 是一个常见的工具,它能统计文本文件的字符数.单词数和行数.这个项目要求写一个命令行程序,模仿 ...

  9. java实现wc.exe

    Github地址:https://github.com/ztz1998/wc/tree/master 项目相关要求 实现一个统计程序,它能正确统计程序文件中的字符数.单词数.行数,以及还具备其他扩展功 ...

随机推荐

  1. form表单重置、清空方法记录

    myform 是form的id属性值 1.调用reset()方法 function fomrReset() { document.getElementById("myform"). ...

  2. gtftools软件简单介绍(我自己不建议用,因为我发现不好用)

    1)背景 生物信息学研究经常涉及计算或提取基因的各种特征,如基因ID作图,GC含量计算和不同类型的基因长度,通过操纵基因模型,这些模型通常以GTF格式注释,可从ENSEMBL或GENCODE数据库获得 ...

  3. Easyui-datagrid显示时间的格式化代码

    {field: 'Time', title: '时间', formatter: function (value, row, index) { var date = new Date(value); v ...

  4. VMware克隆CentOS网络配置

    配置网络 如果是克隆CentOS的: vi /etc/udev/rules.d/70-persistent-net.rules 注释掉网络eth0,把最后一个改为eth0,记录下mac地址. vi / ...

  5. 【校招面试 之 C/C++】第13题 C++ 指针和引用的区别

    1.指针和引用的定义和性质区别: (1)指针:指针是一个变量,只不过这个变量存储的是一个地址,指向内存的一个存储单元:而引用跟原来的变量实质上是同一个东西,只不过是原变量的一个别名而已.如: int ...

  6. Django基础教程

    实例练习1-提交数据并展示 1.app_01下的views.py info_list=[] def userInfor(req): if req.method=="POST": u ...

  7. 注册带有Portal功能的DYN365_ENTERPRISE_PLAN1地址

    使用官方进入的注册页面注册后试用,发现没有Portal功能. https://trials.dynamics.com/Dynamics365/Signup 使用以下的地址注册可以产生Portal ht ...

  8. db2 查看表空间使用率

    1. 统计所有节点表空间使用率 select substr(TABLESPACE_NAME,1,20) as TBSPC_NAME,bigint(TOTAL_PAGES * PAGE_SIZE)/10 ...

  9. SECURITY_ATTRIBUTES 实现最低权限总结

    SetSecurityDescriptorDacl函数可以用来设置DACL中的信息.如果一个DACL已经在security descriptor中存在,那么此DACL将被替换.值得注意的是MSDN中的 ...

  10. 如何处理好前后端分离的 API 问题(转载自知乎)

    9 个月前 API 都搞不好,还怎么当程序员?如果 API 设计只是后台的活,为什么还需要前端工程师. 作为一个程序员,我讨厌那些没有文档的库.我们就好像在操纵一个黑盒一样,预期不了它的正常行为是什么 ...