【C】字符统计程序

Github项目源码地址:https://github.com/ututono/software-programmen

  • 任务要求

wc.exe 是一个常见的工具,它能统计文本文件的字符数、单词数和行数。这个项目要求写一个命令行程序,模仿已有wc.exe 的功能,并加以扩充,给出某程序设计语言源文件的字符数、单词数和行数。
实现一个统计程序,它能正确统计程序文件中的字符数、单词数、行数,以及还具备其他扩展功能,并能够快速地处理多个文件。
具体功能要求:

  • 基本功能列表:(完成)
wc.exe -c     //返回文件 file.c 的字符数
wc.exe -w    //返回文件 file.c 的词的数目  
wc.exe -l      //返回文件 file.c 的行数
  • 扩展功能:(完成)
-s   递归处理目录下符合条件的文件。
-a   返回更复杂的数据(代码行 / 空行 / 注释行)。
  • 高级功能:(完成)

  -x 参数。这个参数单独使用。如果命令行有这个参数,则程序会显示图形界面,用户可以通过界面选取单个文件,程序就会显示文件的字符数、行数等全部统计信息。

  • PSP

PSP2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟)
Planning 计划  30  
Estimate 估计时间  1000  1200
Development 开发  800  800
Analysis 需求分析  10  10
Design Spec 生成设计文档  20  20
Design Review 审计复审  30  20
Coding Standard 代码规范  30  60
Design 具体设计  120  180
Coding 具体编码  600  800
Code Review 代码复审  300  600
Test 测试  200  400
Reporting 报告  60  60

Test Report

测试报告  60  60
Size Measurement 计算工作量  30  30

Postmorem & 

Process Improvement Plan

事后总结  100  180
合计      

 

  • 解题思路

    对程序简单分析,将其主要分为三个部分

    1. 对字数、行数做分析和统计的函数
    2. 对文件进行查询操作的函数
    3. GUI界面

    对于第一点,程序的整体代码并不复杂,只是起初在对于扩展功能中的空行、注释行、代码行的定义有所混淆

    满足空行的条件: 

    1. 除制表符以外,每行空行只能出现至多一次的 “}” 或 “{”

  满足代码行的条件:

    1. 除了 “}” 或 “{”和制表符,每行代码行至少有一个或以上的字符

  满足空行的条件

    1. 在满足空行的条件下,带有“//”或“/*”(即,不是所有带“//”或“/*”都是注释行,也有可能是代码行)

    第二点通过查阅C中关于文件操作的函数得以解决

    第三点通过查阅之后之后,发现通过C来写GUI界面主要有以下几点:

  • 通过Windows API编写

    较为复杂,入门时间成本较大,不适合短时间开发,参考图书《Windows程序设计》

  • 通过MFC

    是微软公司提供的一个类库,以C++类的形式封装了Windows API,并且包含一个应用程序框架,其中包含大量Windows句柄封装类和很多Windows的内建控件和组件的封装类。

  • 通过一些第三方作者提供的库
  • 设计实现过程

    代码主要函数

 1 //基本功能
 2 int CharCount(char *path);        //字符统计函数 -c
 3 int WordCount(char *path);        //单词统计函数 -w
 4 int LineCount(char *path);        //函数统计函数 -l
 5 
 6 void UebrigFunktion(char *path);    //复杂行数统计函数
 7 int EmptylineCount(char *path);        //空行统计函数
 8 int CoCount(char *path);            //注释行统计函数
 9 int CodeCount(char *path);        //代码统计函数
10 
11 void Filefind(char *path,char *filename);        //递归查找文件
  • 代码说明

  空行统计代码,考虑的特殊情况比较多,包括"{"或"}"前后都是制表符等情况

 1     while (!feof(fp))
 2     {
 3         int tag = 0;
 4         int len = 0;
 5         int tag1 = 0;                                                //tag1<2表示行内只有格式控制符或者单个 '}' '{'
 6         if (fgets(str, sizeof(str), fp))
 7         {
 8                 for(len = 0;(len<strlen(str)&&(tag1<2));len++)
 9                 {
10                     if (str[0] == '\n')
11                     {
12                         n++;
13                         break;
14                     }
15                     else if (!(str[len] == '\n' || str[len] == '\t' || str[len] == ' '))
16                     {
17                         if (str[len] == '{' || str[len] == '}'&& !tag1)
18                             tag1=1;
19                         else tag1 = 2;
20                     }
21                     if (len == strlen(str) - 1) n++;                //如果行内只有格式控制符或者单个 '}' '{'则为空行
22                 } 
23         }

  

  第二点的文件操作在实现的时候主要学习了一些文件的操作方法,尤其是有关于句柄

 1 void Filefind(char * path,char *filename)                    //$ review:check chinese word
 2 {
 3     HANDLE Find;
 4     WIN32_FIND_DATA finddata;
 5     char dir[200];
 6     char dirChoose[200];
 7     int n = 0;
 8 
 9     strcpy(dir, path);
10     strcat(dir, "\\*.*");                            //这里一定要指明通配符,不然不会读取所有文件和目录
11     Find = FindFirstFile(charstrtowcharstr(dir), &finddata);
12     do
13     {
14         if ((finddata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY != 0))                //判断是否具有某个属性,可以用按位and运算符(&)
15         {
16             if (strcmp(wchartochar(finddata.cFileName), ".") != 0 && strcmp(wchartochar(finddata.cFileName), "..") != 0)        //一旦找到'.'或"..",则不为空文件夹
17             {
18                 strcpy(dir, path);
19                 strcat(dir, "\\");
20                 strcat(dir, wchartochar(finddata.cFileName));
21                 Filefind(dir, filename);
22             }
23         }
24         else
25         {
26             
27             if (MatchWithAsteriskW(wchartochar(finddata.cFileName), filename))    //文件判断
28             {
29                 strcpy(m_path[n++].filename,wchartochar(finddata.cFileName));
30                 printf("%2d Lage ist:%s\\%s\n", n,path,wchartochar(finddata.cFileName));
31             }
32         }
33     } while (FindNextFile(Find,&finddata));
34     m_path;
35     printf("choose the num(nur Num):");
36     scanf("%d", &n);
37     strcat(path, "\\");
38     liemain(strcat(path, m_path[n - 1].filename));
39     FindClose(Find);
40 }

  

  此外因为<windows.h>中的函数都是使用w*类变量,例如wchar、LPCWSTR(* wchar)。

  wchar_t是采用win32两个字节UNICODE编码,可以正确存储汉字。

  char属于C和C++的最常见的基本数据类型,长度为一个字节,只能存储ASII码。

下面这行代码不会报错但是c的值却不是汉字‘汉’,因为只有一个字节,所以无法存储,打印出来是乱码(?)。
char c = '汉';
wchar_t是采用win32两个字节UNICODE编码,可以正确存储汉字。

对于两种类型的数组同样都可以保存汉字,下面的两行代码没有错误
char* c = "汉字";
wchar_t* cc = L"汉字";
但是长度不同,c的长度是5而cc的长度是3,一个汉字同样需要占据两个char的存储空间。
在vc++6.0和vs中一个字符串默认是按照单字节编码,也就是char*类型,如果要使用两个字节编码wchar_t*存储字符串,
需要在字符串前添加L或使用TEXT("你的字符串")函数。

  在调用之前的函数时会出现值类型转换不兼容的问题,在查阅相关资料之后,使用了以下函数

 1 char * wchartochar(const wchar_t* wchar)                    //WCHAR转换为CHAR
 2 {
 3     char * m_char;
 4     int len = WideCharToMultiByte(CP_ACP, 0, wchar, wcslen(wchar), NULL, 0, NULL, NULL);
 5     m_char = new char[len + 1];
 6     WideCharToMultiByte(CP_ACP, 0, wchar, wcslen(wchar), m_char, len, NULL, NULL);
 7     m_char[len] = '\0';
 8     return m_char;
 9 }
10 
11 const LPCWSTR charstrtowcharstr(char *charstr)        //charstr转化成LPCWSTR
12 {
13 
14     WCHAR wszClassName[256];
15     memset(wszClassName, 0, sizeof(wszClassName));
16     MultiByteToWideChar(CP_ACP, 0, charstr, strlen(charstr) + 1, wszClassName,sizeof(wszClassName) / sizeof(wszClassName[0]));
17     return wszClassName;
18 }

  MFC相关函数:因为直接套用MFC的框架,所以GUI的界面基本不用写,只要处理Button的事件相应就行。

 1 void CMFCApplication2Dlg::OnClickedSaveButton()
 2 {
 3     UpdateData(TRUE);    
 4     char *pathstr = wchartochar(m_filename_edit);
 5     m_chc_edit = CharCount(pathstr);
 6     m_wc_edit = WordCount(pathstr);
 7     m_linec_edit = LineCount(pathstr);
 8     m_emptyline_edit = EmptylineCount(pathstr);
 9     m_coc_edit = CodeCount(pathstr);
10     m_commitoutc_edit = CoCount(pathstr);
11 
12     UpdateData(FALSE);
13 }
  •  测试运行

 (单元测试等占位)

GUI界面选择文件

GUI界面计算

  • 项目小结

  1. 对Git有了初步了解,以前虽然也使用过git,但是没有这次碰到的问题多,实际上在开发工程的市场中有接近一半的时间在调试Git的各种问题,主要碰到过但不仅包括以下几点
  1. .gitignore不起作用,导致push的文件过大
  2. 给本地仓库瘦身,删除本地仓库中的大文件
  3. 两个不同远程仓库的连接冲突问题
  4. clone远程仓库后新建的本地仓库无法与相关联
  5. ssh证书所引起的一系列问题

  2. 翻阅了《构建之法》,虽不甚了解,但是也依葫芦画瓢慢慢学习

  3.了解并使用了一些基础的C语言中文件相关的函数

  4.软件开发中的测试方法

  5.C/C++的图形化界面开发方法MFC的简单尝试

  • 参考

  1. MFC入门编程系列:http://www.jizhuomi.com/software/147.html
  2. C对汉字的处理:http://www.cnblogs.com/this-543273659/archive/2011/07/26/2117200.html
  3. Git删除大文件:https://blog.csdn.net/zcf1002797280/article/details/50723783
  4. ,gitignore无效处理方法:https://blog.csdn.net/q664243624/article/details/78343400
  5. Git忽略处理规则:https://www.cnblogs.com/kevingrace/p/5690241.html
  6. web端VSTS使用方法:http://www.cnblogs.com/jiangyongtao/p/8285171.html

猜你喜欢

转载自www.cnblogs.com/ZugangTurs/p/9644283.html