zoukankan      html  css  js  c++  java
  • 个人项目作业Word Count

    个人项目作业

    1.Github地址

    https://github.com/CLSgGhost/SE_work

    2.项目相关需求

    wc.exe 是一个常见的工具,它能统计文本文件的字符数、单词数和行数。这个项目要求写一个命令行程序,模仿已有wc.exe 的功能,并加以扩充,给出某程序设计语言源文件的字符数、单词数和行数。

    实现一个统计程序,它能正确统计程序文件中的字符数、单词数、行数,以及还具备其他扩展功能,并能够快速地处理多个文件。
    具体功能要求:
    程序处理用户需求的模式为:

    wc.exe [parameter] [file_name]

    基本功能列表:

    wc.exe -c file.c     //返回文件 file.c 的字符数

    wc.exe -w file.c    //返回文件 file.c 的词的数目  

    wc.exe -l file.c      //返回文件 file.c 的行数

    扩展功能:
        -s   递归处理目录下符合条件的文件。
        -a   返回更复杂的数据(代码行 / 空行 / 注释行)。

    空行:本行全部是空格或格式控制字符,如果包括代码,则只有不超过一个可显示的字符,例如“{”。

    代码行:本行包括多于一个字符的代码。

    注释行:本行不是代码行,并且本行包括注释。一个有趣的例子是有些程序员会在单字符后面加注释:

        } //注释
    在这种情况下,这一行属于注释行。

    [file_name]: 文件或目录名,可以处理一般通配符。
    高级功能:

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

    需求举例:
      wc.exe -s -a *.c

    返回当前目录及子目录中所有*.c 文件的代码行数、空行数、注释行数。

    3.PSP估计开发时间

    PSP2.1Personal Software Process Stages预估耗时(分钟)
    Planning 计划  20
    · Estimate · 估计这个任务需要多少时间  20
    Development 开发  635
    · Analysis · 需求分析 (包括学习新技术)  240
    · Design Spec · 生成设计文档  20
    · Design Review · 设计复审 (和同事审核设计文档)  10
    · Coding Standard · 代码规范 (为目前的开发制定合适的规范)  5
    · Design · 具体设计  60
    · Coding · 具体编码  120
    · Code Review · 代码复审  60
    · Test · 测试(自我测试,修改代码,提交修改)  120
    Reporting 报告  60
    · Test Report · 测试报告  20
    · Size Measurement · 计算工作量  20
    · Postmortem & Process Improvement Plan · 事后总结, 并提出过程改进计划  20
      合计  715

    4.解题思路

    • 使用的编程语言:以往都是用C写代码,这次项目尝试用C++写一下。
    • 需要学习到的知识:string流的使用、正则表达式等。
    • 寻找资料的方式:通过博客学习,实在难以理解时询问有经验的朋友。
    • 思考细节:因为要做的是一个word count程序,而word count是存在的一个工具,可以通过了解word count的详细功能来进一步理解需求,并模  仿word count完成自己的程序。
    •  遇到的困难:以前没有接触到处理文件的程序写法,各种处理文件的函数处理方式十分陌生,容易遇到难以发现的bug。

    5.设计实现过程

    • 输入输出:按照需求上的输入方式制定用户输入格式,给出指令菜单,然后按指令给出相关输出。
    • 功能实现方式:需要实现的功能很明确,代码量应该不会很大,采用一个功能一个函数的方式实现,通过主函数调用各个功能的函数。  将所有  函数定义在一个类里面,主函数直接调用。                
    • 功能函数定义:

        int Char_count(string File_name);      //统计字符数
        int Word_count(string File_name);     //统计单词数
        int Line_count(string File_name);       //统计行数
        int NullLine_count(string File_name);                         //统计空行数
        int ComLine_count(string File_name);                        //统计注释行数
        int CodeLine_count(string File_name, int L1, int L2); //统计代码行数

    • 实现细节: 注意到  行数 = 空行数 + 注释行数 + 代码行数,干脆只实现行数、空函数和注释行数的统计函数,剩下代码行数的统计可以直接用  行数 - 空行数 - 注释行数  得到,减少开发时间。

    6.代码说明

       //主函数

     1 int main()
     2 {
     3     char c;
     4     Word_Count wc;
     5     ifstream file;
     6     string Order, File_name;
     7     cout << "输入格式:wc.exe(空格)[parameter](空格)[file_name]" << endl << endl;
     8     cout << "功能列表:-c 统计文件字符数" << endl;
     9     cout << "          -w 统计文件单词数" << endl;
    10     cout << "          -l 统计文行数数" << endl;
    11     cout << "          -a 统计文件空行数、注释行数、代码行数" << endl << endl;
    12     while (1)
    13     {
    14         cout << "wc.exe" << " ";
    15         cin >> Order >> File_name;
    16         file.open(File_name, ios::in);
    17         if (!file.is_open())    //查找文件失败
    18         {
    19             cout << "文件不存在,无法打开" << endl << endl;
    20             continue;
    21         }
    22         c = file.get();
    23         if (c == EOF)        //文件为空
    24         {
    25             cout << "文件为空" << endl;
    26         }
    27         if (Order[0] == '-')
    28         {
    29             switch (Order[1])
    30             {
    31             case 'c':wc.Ch_count = wc.Char_count(File_name);    //统计字符数
    32                 cout << "文件字符数为:" << wc.Ch_count << endl << endl;
    33                 break;
    34             case 'w':wc.Wo_count = wc.Word_count(File_name);    //统计单词数
    35                 cout << "文件单词数为:" << wc.Wo_count << endl << endl;
    36                 break;
    37             case 'l':wc.Li_count = wc.Line_count(File_name);    //统计行数
    38                 cout << "文件总行数为:" << wc.Li_count << endl << endl;
    39                 break;
    40             case 'a':
    41                 wc.NuLi_count = wc.NullLine_count(File_name);   //统计空行数
    42                 wc.CmLi_count = wc.ComLine_count(File_name);    //统计空行数
    43                 wc.CdLi_count = wc.CodeLine_count(File_name, wc.NuLi_count, wc.CmLi_count);//统计代码行数
    44                 cout << "文件空行数为:" << wc.NuLi_count << endl;
    45                 cout << "文件注释行数为:" << wc.CmLi_count << endl;
    46                 cout << "文件代码行数为:" << wc.CdLi_count << endl << endl;
    47                 break;
    48             default:
    49                 cout << "无效指令" << endl << endl;
    50                 break;
    51             }
    52         }
    53         file.close();
    54     }
    55     system("pause");
    56     return 0;
    57 }

      //统计字符数

     1 int Word_Count::Char_count(string File_name)   //统计字符数
     2 {
     3     int n1 = 0;
     4     char ch;
     5     ifstream f;
     6     f.open(File_name, ios::in);
     7     f >> ch;
     8     while (!f.eof())
     9     {
    10         f >> ch;        //逐个读入字符并统计数量
    11         n1++;
    12     }
    13     f.close();
    14     return n1;
    15 }

      //统计单词数

     1 int Word_Count::Word_count(string File_name)   //统计单词数
     2 {
     3     int n2 = 0;
     4     char ch;
     5     ifstream f;
     6     f.open(File_name, ios::in);
     7     while (!f.eof())
     8     {
     9         ch = f.get();
    10         if ((ch >= 'A'&& ch <= 'Z') || (ch >= 'a'&& ch <= 'z'))  //发现单词
    11         {
    12             while ((ch >= 'A'&& ch <= 'Z') || (ch >= 'a'&& ch <= 'z'))
    13             {
    14                 ch = f.get();           //读取字符直到退出单词
    15             }
    16             n2++;     //单词计数器+1
    17         }
    18     }
    19     f.close();
    20     return n2;
    21 }

    //统计行数

     1 int Word_Count::Line_count(string File_name)   //统计行数
     2 {
     3     int n3 = 0;
     4     char ch;
     5     ifstream f;
     6     f.open(File_name, ios::in);
     7     ch = f.get();
     8     if (ch == EOF)      //文件为空则返回0
     9     {
    10         return 0;
    11     }
    12     while (!f.eof())
    13     {
    14         if (ch == '\n')   //读取到换行符时行数+1
    15         {
    16             n3++;
    17         }
    18         ch = f.get();
    19     }
    20     f.close();
    21     return n3 + 1;
    22 }

      //统计空行数

     1 int Word_Count::NullLine_count(string File_name)   //统计空行数
     2 {
     3     int n4 = 0, i = 0;
     4     char ch;
     5     char str[2000];
     6     bool is_comline = 0;    //判断当前行是否在注释行"/*...*/"内
     7     string s;
     8     string pattern = "^[\\s]{1,}[\\S]?";  //正则表达式,匹配任何空字符一个以上和非空字符0或1个
     9     regex exception(pattern);
    10     fstream f;
    11     f.open(File_name, ios::in);   //打开文件
    12     ch = f.get();
    13     if (ch == EOF)      //文件为空则返回0
    14     {
    15         return 0;
    16     }
    17     while (!f.eof())   //判断文件是否读取完毕
    18     {
    19         getline(f, s);     //逐行读取文件
    20         i = 0;    //i初始化
    21         if (!s.empty())
    22         {
    23             strcpy_s(str, s.c_str());  //string非空就则转换位字符数组
    24         }
    25         while (str[i] == ' ' || str[i] == '\t')   //过滤空格和'\t'
    26         {
    27             i++;
    28         }
    29         if (str[i] == '/' && str[i + 1] == '*')  //读取到'/*',开始注释行识别
    30         {
    31             is_comline = 1;
    32             i += 2;
    33         }
    34         while (is_comline == 1 && str[i] != '\0')
    35         {
    36             if (str[i] == '*' && str[i + 1] == '/')  //读取到'*/',结束注释行识别
    37             {
    38                 is_comline = 0;
    39             }
    40             i++;
    41         }
    42         s.erase(0, 1);
    43         if (s.empty() && is_comline == 0)     //判断读取的行是否只有回车换行符
    44         {
    45             n4++;
    46             continue;
    47         }
    48         if (regex_match(s, exception) && is_comline == 0)
    49         {
    50             n4++;        //匹配任何空字1个以上,非空字符只有0或1个的空行 ,且不在注释行内则空行数增加
    51         }
    52     }
    53     f.close();
    54     return n4;
    55 }

      //统计注释行数

     1 int Word_Count::ComLine_count(string File_name)   //统计注释行数
     2 {                           
     3     int n5 = 0, i = 0;
     4     char str[2000];
     5     bool is_comline = 0;
     6     ifstream f;
     7     f.open(File_name, ios::in);   //打开文件
     8     while (!f.eof())   //判断文件是否读取完毕
     9     {
    10         f.getline(str, 2000);     //逐行读取文件
    11         i = 0;      //i初始化
    12         if (str[0] == '}')
    13         {
    14             i++;
    15         }
    16         while (str[i] == ' ' || str[i] == '\t')   //过滤空格和'\t'
    17         {
    18             i++;
    19         }
    20         if (str[i] == '/' && str[i + 1] == '/')  //读取'//'
    21         {
    22             if (is_comline == 0)   //当前行不在注释'/*...*/'内,注释行加一
    23             {
    24                 n5++; 
    25                 continue;
    26             }
    27         }
    28         if (str[i] == '/' && str[i + 1] == '*')  //读取到'/*',开始注释行计算
    29         {
    30             is_comline = 1;
    31             i += 2;
    32         }
    33         if (is_comline == 1)
    34         {
    35             n5++;                //当前行在注释'/*...*/'内,注释行加一 
    36         }
    37         while (is_comline == 1 && str[i] != '\0')
    38         {
    39             if (str[i] == '*' && str[i + 1] == '/')  //读取到'*/',结束注释行计算
    40             {
    41                 is_comline = 0;
    42             }
    43             i++;
    44         }
    45     }
    46     f.close();
    47     return n5;
    48 } //注:不考虑注释符'/*...*/'不闭合的情况。若出现'/*'而没有'*/',默认文本本身出错且'/*'以下全为注释行

      //统计代码行数

    1 int Word_Count::CodeLine_count(string File_name, int L1,int L2)   //统计代码行数
    2 {
    3     int n6 = 0;
    4     int    L = 0;  //定义总行数
    5     Word_Count w;
    6     L = w.Line_count(File_name);
    7     n6 = L - L1 - L2;    //注释行数 = 总行数 - 空行数 - 注释行数
    8     return n6;
    9 }

    7.测试运行

    • 已实现功能:

                -c   -w   -l   -a   

    • 具体测试截图:

          //空文件测试

         //单字符文件测试

         //单个词文件测试

     

         //单行文件测试

        //典型文件测试

      //错误输入提示

    8.完整PSP

    PSP2.1

    Personal Software Process Stages

    预估耗时(分钟)

    实际耗时(分钟)

    Planning

    计划

     20

     20

    · Estimate

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

     20

     20

    Development

    开发

     635

     725

    · Analysis

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

     240

     240

    · Design Spec

    · 生成设计文档

     20

     20

    · Design Review

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

    10

     10

    · Coding Standard

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

     5

     5

    · Design

    · 具体设计

     60

     60

    · Coding

    · 具体编码

     120

     150

    · Code Review

    · 代码复审

     60

     90

    · Test

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

     120

     150

    Reporting

    报告

     60

     90

    · Test Report

    · 测试报告

     20

     20

    · Size Measurement

    · 计算工作量

     20

     20

    · Postmortem & Process Improvement Plan

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

     20

     50

    合计

     715

     835

     

    9.项目小结

           看到要做个人项目作业的时候其实我还是比较懵逼的,感觉还什么都不会,然后就要来写个人项目,不过还是一点点看博客,一点点学,终于算是做了出来,由于个人能力问题与时间问题,很多功能都还没实现,希望在以后的学习中能学习到其他功能的实现方法。

          从PSP来看,实际开发时间远超预估,即使是预估已有所保留空余时间的情况下。从而看出两个问题:1.对自己编程水平还不够了解。2.对我个人来说项目难度超出预期。而且就开发过程来看,程序中许多写法还有很大的优化空间。希望在以后的学习里能不断磨练自己,让自己成长为一个有能力的软件开发者。

  • 相关阅读:
    图像处理笔记(二十一):halcon在图像处理中的运用
    图像处理笔记(二十):LAWS纹理滤波应用于缺陷检测
    图像处理笔记(十九):分类器之高斯混合模型
    图像处理笔记(十八):模板匹配
    图像处理笔记(十七):再看傅里叶变换
    图像处理笔记(十六)
    python列表(list)的技巧及高级操作
    python多线程
    CD/CI的概念
    网络
  • 原文地址:https://www.cnblogs.com/clsgghost/p/12493426.html
Copyright © 2011-2022 走看看