软件工程第一次作业:个人项目WC

github地址 :https://github.com/zhangabing/First-test-WC

个人项目:WC

1.项目要求

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

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

  • 程序处理用户需求的模式为:

  • 基本功能列表:

    • wc.exe -c file.c //返回文件 file.c 的字符数
    • wc.exe -w file.c //返回文件 file.c 的词的数目
    • wc.exe -l file.c //返回文件 file.c 的行数
  • 扩展功能:

    • -s 递归处理目录下符合条件的文件。
      --a 返回更复杂的数据(代码行 / 空行 / 注释行)。
      • 空行:本行全部是空格或格式控制字符,如果包括代码,则只有不超过一个可显示的字符,例如“{”。
      • 代码行:本行包括多于一个字符的代码。
      • 注释行:本行不是代码行,并且本行包括注释。一个有趣的例子是有些程序员会在单字符后面加注释:
      • } //注释
      • 在这种情况下,这一行属于注释行。
  • 高级功能:

    • -x 参数。这个参数单独使用。如果命令行有这个参数,则程序会显示图形界面,用户可以通过界面选取单个文件,程序就会显示文件的字符数、行数等全部统计信息。
    • 需求举例:
         - wc.exe -s -a .c
      - 返回当前目录及子目录中所有
      .c 文件的代码行数、空行数、注释行数。

2.遇到的困难及解决方法

主要困难有

  1. 当双引号出现在注释之中时
  2. 当注释符出现在双引号或者是单引号之中时
  3. 当块注释符号出现在行注释符之后时
  4. 当块注释结束之后进入代码行,但是行末再次出现行注释时
  5. 某一行既可以是代码行,也可以是注释行,或者既可以是注释行,也可以是空行

一开始并没有考虑到第五点,然后就写出了一次程序,但是在后来听闻同学找了老师问清楚要求之后,整份代码都进行了重新书写,并且判断注释行,代码行,空行比较麻烦,最终使用了几个bool类型标记终于完成这一功能

当我完成上面所述的问题之后,我觉得我的代码实现能力涨了一大截,并且思考是否还有更为极端得情况。

3.关键代码or设计说明

本文实现了基本功能,和扩展功能
先进行文件内容的读取

bool input(FILE * fp)
//读入文本
 {
     str = "";
     char s;
     while((s = fgetc(fp)) != EOF)
         str = str + s;
     str = str + '\n';
     if(str.length() == 1)
     {
         Null = true;
     }
     return Null;
 }

基本功能:直接调用相对应的函数完成

void Line()
//统计行数
{
    int num = 0;
    for(int i = 0; i < str.length(); i ++)
    {
        if(str[i] == '\n')   num ++;
    }
    if(!Null)
        printf("行数    :%d\n", num);
}

void Char()
//统计字符
{
    int num = 0;
    for(int i = 0; i < str.length(); i ++)
    {
        if(str[i] != ' ' && str[i] != '\n' && str[i] != '\t')
            num ++;
    }
    if(!Null)
        printf("字符个数 :%d\n", num);
}

void Words()
//统计单词
{
    int num = 0;
    bool flag = 0;
    for(int i = 0; i < str.length(); i ++)
    {
        if(str[i] <= 'z' && str[i] >= 'a' || str[i] <= 'Z' && str[i] >= 'A' || str[i] == '_')
        {
            if(!flag)   num ++;
            flag = true;
        }
        else flag = false;
    }
    if(!Null)
        printf("单词个数 :%d\n", num);
}

调用calc直接对读入的文件进行统计代码行,注释行,空行

void Calc()
{
bool line_comment = false;  //行注释
bool block_comment = false; //块注释标记
bool comment_exist = false; //注释出现过标记

string s_comment = "";
string s_code = "";
//注释里面的字符串和代码里面的字符串

if(str[0] == '\n')
    Empty ++;
else  if(str[0] != ' ' && str[0] != '\t')
    s_code = s_code + str[0];

for(int i = 1; i < str.length(); i ++)
{
    if(str[i] == ' ' || str[i] == '\t')
        continue ;

    if(str[i] == '\n')
    {
        if(comment_exist || line_comment || block_comment)
            Comment ++;
        //注释判断

        if(s_comment.length() == 0)
        {
            if(s_code.length() == 0)
                Empty ++;

            if(s_code.length() == 1 && (s_code[0] == '{' || s_code[0] == '}' || s_code[0] == ';'))
                Empty ++;
        }
        //空行判断

        if(s_code.length() > 1 || (s_code[0] != '{' && s_code[0] != '}' && s_code[0] != ';'))
            Code ++;
        //代码行判断

        s_code = "";
        s_comment = "";
        line_comment = false;
        comment_exist = false;
        //换行之后初始化
    }

    else if(line_comment)
    //行注释中
    {
        s_comment = s_comment + str[i];
        comment_exist = true;
    }

    else if(block_comment)
    //块注释中
    {
        s_comment = s_comment + str[i];
        comment_exist = true;

        if(str[i - 1] == '*' && str[i] == '/')
            block_comment = false;
        //块注释终止
    }

    else if(str[i - 1] == '/' && str[i] == '/')
    //将代码字符串最后一个 / 保存到注释字符串之中,并行注释标记为真
    {
        s_code = s_code.substr(0, s_code.length() - 1);
        s_comment = s_comment + str[i - 1] + str[i];

        line_comment = true;
        comment_exist = true;
    }

    else if(str[i - 1] == '/' && str[i] == '*')
    //将代码字符串最后一个 / 保存到注释字符串之中,并块注释标记为真
    {
        s_code = s_code.substr(0, s_code.length() - 1);
        s_comment = s_comment + str[i - 1] + str[i];
        block_comment = true;
        comment_exist = true;
    }

    else if(str[i] == '\"')
    //读到双引号时,直接循环到下一个双引号, 并保存至代码字符串之中
    {
        s_code = s_code + str[i];
        while(str[++ i] != '\"')
        {
            s_code = s_code + str[i];
        }
        s_code = s_code + str[i];
    }

    else if(str[i] == '\'')
    //读到单引号时,直接循环到下一个单引号, 并保存至代码字符串之中
    {
        s_code = s_code + str[i];
        while(str[++ i] != '\'')
        {
            s_code = s_code + str[i];
        }
        s_code = s_code + str[i];
    }

    else
    //普通字符
        s_code = s_code + str[i];
}

if(!Null)
{
    printf("注释行数 : %d\n", Comment);
    printf("代码行数 : %d\n", Code);
    printf("空行数   : %d\n", Empty);
}

4.测试报告

由于技术有限,笔者采取的是手工测试

第一组测试结果如下:
如图
这里写图片描述

第二组测试结果如下:
这里写图片描述

第三组测试结果如下:
这里写图片描述

第四组测试结果如下:
这里写图片描述

这里写图片描述

5.PSP

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

| 第N周 | 新增代码行 | 累计代码 | 本周学习耗时 | 累计学习耗时 | 重要成长 |
|-----------------------------------------|-----------------------------------------|------------------|------------------|-----------------------|
|1 | 100 | 100 | 8 | 8 | 把文件各个情况捋清,并完成基本功能|
|2 | 215| 215| 11.5 | 19.5 | 学会C文件的读取,并将扩展功能完善|

posted @ 2018-09-11 19:33  3116005161张秉坤  阅读(130)  评论(0编辑  收藏  举报