写在最前:

参考17079张武科同学的代码,故博文中形如详细代码设计等部分引用了张武科的博文,具体引用部分不详细标出,其他部分仍为本人原创

github地址

https://github.com/mrlandiao/wc

PSP表格

PSP2.1

PSP阶段

预估耗时(分钟)

实际耗时(分钟)

Planning

计划

25

45

· Estimate

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

25

35

Development

开发

700

1000

· Analysis

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

150

200

· Design Spec

· 生成设计文档

10

20

· Design Review

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

30

35

· Coding Standard

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

10

20

· Design

· 具体设计

60

70

· Coding

· 具体编码

600

700

· Code Review

· 代码复审

100

150

· Test

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

200

200

Reporting

报告

80

100

· Test Report

· 测试报告

30

40

· Size Measurement

· 计算工作量

10

20

· Postmortem & Process Improvement Plan

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

15

25

 

合计

2045

2660

解题思路

参考上学期编写的词法分析和语法分析程序的基本功能,对其进行修改,得到main函数。利用控制台执行exe文件,通过传参的不同来实现所要求的功能

程序设计实现过程

本项目采用C语言实现,除main函数外,还有多个自定义函数,其中两个最主要的函数为count()和none(),count()用来统计单词数、行数、注释行数,none()用来统计空行数。

main()函数根据传入的形参的不同,完成不同的输出。其余自定义行数比较简单,下面代码说明中会以isNewline()函数为例进行解释。

代码说明

count()函数用以统计单词数、行数、注释行数,函数中有单词判断,没检测出一个单词word_num+1;每遇到一个'\n',line_num+1;没有到注释行,note_num+1,如果是/*note*/注释,在主是内部没出现一次‘\n’,note_num+1。

docvalues统计 word的统计函数_docvalues统计

int count()//统计单词数、行数、注释行数
{
    get();
    clearToken();
    while (isSpace(ch) || isNewline(ch) || isTab(ch) || isComma(ch))
    {
        if (isNewline(ch)) line_num++;
        get();
    }
    if (isStar(ch))
    {
        catToken(ch);
    }
    else if (isDivi(ch))
    {
        catToken(ch);
        get();
        if (isStar(ch))
        {
            note_num++;
            catToken(ch);
            do
            {
                do
                {
                    get();
                    if (isNewline(ch))
                    {
                        note_num++;
                        line_num++;
                    }

                } while (!isStar(ch));
                do
                {
                    get();
                    if (isNewline(ch))
                    {
                        note_num++;
                        line_num++;
                    }
                    if (isDivi(ch))
                    {
                        catToken(ch);
                        return 0;
                    }
                } while (isStar(ch));
            } while (!isStar(ch));
        }
        if (isDivi(ch))
        {
            catToken(ch);
            do
            {
                get();
            } while (!isNewline(ch));
            note_num++;
        }
        if (isNewline(ch))
            line_num++;
    }
    else if (isEnd(ch))
        return 0;
    else
    {
        while (!(isSpace(ch) || isNewline(ch) || isTab(ch) || isComma(ch) || isDivi(ch)))
        {
            catToken(ch);
            get();
        }
        retract();
        if(strcmp(stopWord, "") == 0 || strcmp(token,stopWord)!=0)
           word_num++;
    }
    return 0;
}

docvalues统计 word的统计函数_docvalues统计

以isNewline()为例,解释简单自定义函数:

docvalues统计 word的统计函数_docvalues统计

bool isNewline(char a)
{
    if (a == '\n')
        return true;
    return false;
}

docvalues统计 word的统计函数_docvalues统计

none()函数,根据两个‘\n’中是否小于或等于一个字符来判断是否为空行,满足条件则none_num+1:

docvalues统计 word的统计函数_docvalues统计

void none()//统计空行数
{
    int i,j = 0;
    for (i = 0;; i++)
    {
        if (art[i] == EOF)
            break;
        if (art[i] != '\n'&& art[i] != '\t'&& art[i] != ' ')
        {
            j++;
        }
        if (art[i] == '\n')
        {
            if (j <= 1)
                none_num++;
            j = 0;
        }
    }
}

docvalues统计 word的统计函数_docvalues统计

main()函数,由于功能是逐步添加的,加上自己的代码习惯有待提高,导致main()函数被修改的过于冗杂。重要思想:利用数组flag[7],每一个元素对应一个功能(包括字符数、单词数输出等),为1时表示对应功能执行,反之不执行。

docvalues统计 word的统计函数_docvalues统计

int main(char argc, char* argv[])
{

    if (argc<3)
        printf("请在控制台输入正确命令!\n");
    else
    {
        if (strcmp(argv[0], "wc.exe") != 0)
            printf("可执行文件名输入错误!\n");
        else
        {
            for (int i = 1; i<argc; i++)
            {
                if (strcmp(argv[i], "-c") == 0)
                {
                    flag[0] = 1;
                }
                else if (strcmp(argv[i], "-w") == 0)
                {
                    flag[1] = 1;
                }
                else if (strcmp(argv[i], "-l") == 0)
                {
                    flag[2] = 1;
                }
                else if (strcmp(argv[i], "-o") == 0)
                {
                    flag[3] = 1;
                }
                else if (strcmp(argv[i], "-s") == 0)
                {
                    flag[4] = 1;
                }
                else if (strcmp(argv[i], "-a") == 0)
                {
                    flag[5] = 1;
                }
                else if (strcmp(argv[i], "-e") == 0)
                {
                    flag[6] = 1;
                }
            }
        }
    }

    if (flag[4] == 1)
    {
        _finddata_t sFind;
        long lResult = 0;
        lResult = _findfirst("*.c", &sFind);
        if (lResult == -1) {
            printf("没有找到文件。");
            return 0;
        }

        int i=0,len;
        do {
            len = strlen(sFind.name);
            strcpy_s(filesName[i], len + 1, sFind.name);//将所有读到的保存到filesname
            file_num++;
            i++;
        } while (_findnext(lResult, &sFind) != -1);
    
        for (int j = 0; j < file_num; j++)
        {
            fopen_s(&fp, filesName[j], "r");
            if (fp == NULL)
                printf("error!\n");
            int i = 0;
            do//获取文件内容
            {
                ch = fgetc(fp);
                art[i++] = ch;
            } while (ch != EOF);
            fclose(fp);
            char_num = i;

            if (flag[6] == 1)//获取停用词
            {
                fopen_s(&fp, "stopList.txt", "a");
                fgets(stopWord, 20, fp);
                fclose(fp);
            }
            do//核心统计
            {
                count();
            } while (!isEnd(ch));
            none();
    
            if (flag[0] == 1)
                printf("%s,字符数: %d \n", filesName[j], char_num);
            if (flag[1] == 1)
                printf("%s,单词数: %d \n", filesName[j], word_num);
            if (flag[2] == 1)
                printf("%s,总行数: %d \n", filesName[j], line_num);
            if (flag[3] == 1)
            {
                fopen_s(&fp, argv[argc - 1], "a");
                if (flag[0] == 1)
                    fprintf(fp, "%s,字符数: %d \n", filesName[j], char_num);
                if (flag[1] == 1)
                    fprintf(fp,"%s,单词数: %d \n", filesName[j], word_num);
                if (flag[2] == 1)
                    fprintf(fp,"%s,总行数: %d \n", filesName[j], line_num);
                if (flag[5] == 1)
                    fprintf(fp, "%s,代码行/空行/注释行: %d/%d/%d \n", filesName[j], line_num - note_num - none_num, none_num, note_num);
                fclose(fp);
            }
            if (flag[5] == 1)
                printf("%s,代码行/空行/注释行: %d/%d/%d \n", filesName[j], line_num - note_num - none_num, none_num, note_num);
            strcpy_s(stopWord,1,"");
            for (int i = 0; i < 1000; i++)
                art[i] = '\0';
            sta = art;
            char_num = 0;
            word_num = 0;
            line_num = 0;
            note_num = 0;
            none_num = 0;
        }
    }

    else
    {
        fopen_s(&fp, "file.c", "r");
        if (fp == NULL)
            printf("error!\n");
        int i = 0;
        do
        {
            ch = fgetc(fp);
            art[i++] = ch;
        } while (ch != EOF);
        fclose(fp);
        char_num = i;

        if (flag[6] == 1)
        {
            fopen_s(&fp, "stopList.txt", "r");
            fgets(stopWord, 20, fp);
            fclose(fp);
        }
        do
        {
            count();
        } while (!isEnd(ch));
        none();

        if (flag[0] == 1)
            printf("file.c,字符数: %d \n", char_num);
        if (flag[1] == 1)
            printf("file.c,单词数: %d \n", word_num);
        if (flag[2] == 1)
            printf("file.c,总行数: %d \n", line_num);
        if (flag[3] == 1)
        {
            fopen_s(&fp, argv[argc - 1], "w");
            if (flag[0] == 1)
                fprintf(fp, "file.c,字符数: %d \n", char_num);
            if (flag[1] == 1)
                fprintf(fp, "file.c,单词数: %d \n", word_num);
            if (flag[2] == 1)
                fprintf(fp, "file.c,总行数: %d \n", line_num);
            if (flag[5] == 1)
                fprintf(fp, "file.c,代码行/空行/注释行: %d/%d/%d \n", line_num - note_num - none_num, none_num, note_num);
            fclose(fp);
        }
        if (flag[5] == 1)
            printf("file.c,代码行/空行/注释行: %d/%d/%d \n", line_num - note_num - none_num, none_num, note_num);
    }
    printf("\n");
    system("pause");
    return 0;
}

docvalues统计 word的统计函数_docvalues统计

测试设计过程

利用“wc.bat”脚本程序,批量处理,测试用例如下:

docvalues统计 word的统计函数_docvalues统计_09

测试结果为

docvalues统计 word的统计函数_i++_10

测试数据集是我自己随意输入的,详情参见同目录下file.c文件,测试输出结果我已经检查,确认无误。需要说明的是其中仅包含 “ { ” 的行算作空行,不算作代码行。

 另外,当“-s”和“-o”命令同时输入时,写入文件之前不会清空文件;仅包含“-o”命令而不包含“-s”命令时,写入文件之前会清空文件。