C语言实现wc.exe

前言

Github地址:https://github.com/starmiku/xiangmu_wc

编程语言:C

项目简介

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 这个参数单独使用。如果命令行有这个参数,则程序会显示图形界面,用户可以通过界面选取单个文件,程序就会显示文件的字符数、行数等全部统计信息。 (未完成)

PSP

PSP2.1预计耗时实际耗时
总体计划2h2.5h
预计完成10h12h
程序开发8h10h
需求分析0.5h1h
设计文档0.5h0.5h
设计复审0.5h0.5h
代码规范0.5h0.5h
具体设计1h1h
具体编码6h8h
代码复审1h1h
程序测试2h2h
程序报告1h1h
测试报告1h0.5h
计算工作量0.5h0.5h
事后总结2.5h2h
总计时间12h14.5h

解题思路

  1. 命令行操作,想到通过C的命令行参数实现。

  2. 行数计算,通过读取'\n'实现。

  3. 字符计算,通过逐一读取字符并排除'\n'和eof实现。

  4. 词数计算,通过读取连续的字母(包括符号.和_)实现。

  5. 空行计算,通过两个换行符之间是否存在字符实现。

  6. 注释行计算,通过读取第一个字符为/进入判断,读取第二个字符为*或者/实现。

  7. 代码行计算,排除空行和注释行之外的即为代码行。

程序流程

程序由主函数和五个功能函数组成。其中test()函数为测试函数,保留作为调试窗口。

1485131-20180914143813595-1854146398.jpg

关键代码

主函数

通过直接读取命令行参数作为程序执行参数,使用while循环提供其他功能的选择。

int main(int argc, char *argv[])
{
    int choose = 0;
    char com; //获取具体命令
    FILE * fp = NULL;
    char* func = (char*)malloc(sizeof(char) * 50); //接收命令参数
    if (argv[2] != NULL && argv[1] != NULL)
    {
        fp = fopen(argv[2], "r");
        func = argv[1];
        com = func[1];
        if (fp == NULL)
        {
            printf("文件打开失败。\n");
            exit(1);
        }
    }
    else
    {
        printf("参数输入错误。\n");
        return 0;
    }
    if (com == 'c')
        choose = 1;
    else if (com == 'w')
        choose = 2;
    else if (com == 'l')
        choose = 3;
    else
        choose = 101;
    while (1)
    {
        switch (choose)
        {
        case 1:
            GetLetter(fp);
            rewind(fp);
            break;
        case 2:
            GetWord(fp);
            rewind(fp);
            break;
        case 3:
            GetLine(fp);
            rewind(fp);
            break;
        case 4:
            MoreData(fp);
            rewind(fp);
            break;
        case 100:
            fclose(fp);
            free(func);
            exit(0);
        case 101:
            printf("错误输入\n\n");
            while (getchar() != '\n') //清空所有输入
                continue;
            break;
        }
        printf("输入:q 退出\t w 获取词数\t l 获取行数\t c 获取字符数\t a 获取更多信息\t");
        scanf("%c", &com);
        getchar();
        if (com == 'c')
            choose = 1;
        else if (com == 'w')
            choose = 2;
        else if (com == 'l')
            choose = 3;
        else if (com == 'a')
            choose = 4;
        else if (com == 'q')
            choose = 100;
        else
            choose = 101;
    }
    //test();
    return 0;
}

功能:获取行数

通过读取'\n'(即ASCII码 10)作为换行标记,如果代码行中出现'\n',fgetc()会分别读取到\和n,不会视作换行。

void GetLine(FILE *f)
{
    int letter = 0, line = 0;
    //接收字符,行数
    int mark = 0;
    while (!feof(f))
    {
        letter = fgetc(f);
        if (letter == '\n')
            line++;
    }
    printf("共有行数 %d\n\n", line);
}

功能:获取词数

如果由连续的字母和'_'则视为词语,如果前后均为符号或空格,单个字母也视作词语。

void GetWord(FILE *f)
{
    int letter = 0, word = 0;
    //接收字符,词数
    int mark = 0;
    //0为非字符,1为字符串
    while (!feof(f))
    {
        letter = fgetc(f);
        if ((letter >= 'a'&&letter <= 'z') || (letter >= 'A'&&letter <= 'Z') || letter == '_')
        {
            if (mark == 0)
                mark = 1;
        }
        else if (letter == '.') //防止头文件和浮点数的'.'被误判
        {
            if (mark == 0 || mark == 1)
                continue;
        }
        else
        {
            if (mark == 1)
            {
                word++;
                mark = 0;
            }
            else
                continue;
        }
    }
    printf("共有词数 %d\n\n", word);
}

功能:获取字符数

将一切能读取的字符均计入字符数,除换行符和eof标志。

void GetLetter(FILE *f)
{
    int letter = 0, num = 0;
    //接收字符,字符数
    while (!feof(f))
    {
        letter = fgetc(f);
        if (letter == '\n') //除换行标记外均视为字符
            continue;
        num++;
    }
    printf("共有字符数 %d\n\n", num - 1);  //除去eof标志
}

拓展:更多数据

先判定是否为空行,如果不为空行则从接收的字符判定为代码行或注释行,通过独立的while循环来读取整行数据,减少判断次数。

void MoreData(FILE *f)
{
    int letter = 0, code = 0, empty = 0, note = 0, mark = 0, notemark = 0;
    /*
    接受字符,代码行数,空行数,注释行数,类型标记,注释行标记
    mark的参数:0空行,1存在格式化字符的空行,2代码行,3注释行
    notemark参数:0未判定,1单行注释,2多行注释
    */
    while (!feof(f))
    {
        letter = fgetc(f);
        if (mark == 0 || mark == 1) //判定空行
        {
            if (letter == ' ')
                continue;
            else if (letter == '\n')
            {
                empty++;
                mark = 0;
                continue;
            }
            else if ((letter == '{' || letter == '}') && mark == 0)
            {
                mark = 1;
                continue;
            }


            else
            {
                if (letter == '/')
                    mark = 3;
                else
                    mark = 2;
            }
        }

        if (mark == 2) //判定代码行
        {
            while (!feof(f) && letter != '\n')
                letter = fgetc(f);
            mark = 0;
            code++;
            continue;
        }

        if (mark == 3) //判定注释行
        {
            while (!feof(f))
            {
                letter = fgetc(f);

                if (letter == '/' && notemark == 0) //单行注释起始判定
                    notemark = 1;
                else if (letter == '*' && notemark == 0) //多行注释起始判定
                    notemark = 2;
                else if (letter == '*' && notemark == 2) //多行注释结束判定
                    notemark = 3;

                if (notemark == 1) //单行注释结束判定
                {
                    while (!feof(f) && letter != '\n')
                        letter = fgetc(f);
                    note++;
                    mark = 0;
                    notemark = 0;
                    break;
                }

                if (notemark == 2)  //多行注释中间行数计算
                {
                    while (!feof(f) && letter != '\n')
                        letter = fgetc(f);
                    note++;
                }

                if (notemark == 3 && letter == '/') //多行注释结束判定
                {
                    while (!feof(f) && letter != '\n')
                        letter = fgetc(f);
                    note++;
                    mark = 0;
                    notemark = 0;
                    break;
                }
                else if (notemark == 3 && letter != '*') //判定是否为注释中的*
                    notemark = 2;
            }
        }
    }
    printf("共有空行数 %d  代码行数 %d  注释行数 %d\n", empty, code - 1, note); //除去eof行
}

测试运行

测试代码

#include<stdio.h>

int main()
{
}

//test

/*
testfile
*/

测试截图

1485131-20180914143831319-1894245519.png

转载于:https://www.cnblogs.com/fallenstarowo/p/9646472.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值