源统计程序(WordCount)
GitHub地址:https://github.com/CloudDawnSun/WC
一.项目要求
1. wc.exe 是一个常见的工具,它能统计文本文件的字符数、单词数和行数。这个项目要求写一个命令行程序,模仿已有wc.exe 的功能,并加以扩充,给出某程序设计语言源文件的字符数、单词数和行数。
2. 实现一个统计程序,它能正确统计程序文件中的字符数、单词数、行数,以及还具备其他扩展功能,并能够快速地处理多个文件。
具体功能要求:
程序处理用户需求的模式为:
wc.exe [parameter] [file_name]
二.解题思路
本来我打算用新学的Java来实现功能,经过尝试过后放弃了,因为我对Java的接口调用和文件操作太不熟悉了。
统计字符数和行数直接就通过fgetc()函数获取标志字符进行判断,而单词我则将英语字符串定义为单词
三.代码
#include<stdio.h> #include<string.h> #include<io.h> #include<stdlib.h> #define MAXSIZE 1024
//统计字符数 void countchar(char* filename) { char c; int charnum = 0; FILE* fp; fp = fopen(filename, "r"); if (fp == NULL) { printf("打开文件失败或文件不存在 "); } else { c = fgetc(fp); while (c != EOF) { charnum++; c = getc(fp); } printf("字符数:%d ", charnum); fclose(fp); } }
1 //统计文件行数 2 void countline(char* filename) 3 { 4 FILE* fp; 5 int linenum = 0; 6 char c; 7 fp = fopen(filename, "r"); 8 if (fp == NULL) 9 { 10 printf("打开文件失败或文件不存在"); 11 return; 12 } 13 c = fgetc(fp); 14 if (c != EOF) linenum++; 15 while (c != EOF) 16 { 17 if (c == ' ' || c == ' ') 18 linenum++; 19 c = fgetc(fp); 20 } 21 printf("行数:%d ", linenum); 22 fclose(fp); 23 }
//统计词数,一个字母算作一个单词
void countword(char* filename)
{
int wordnum = 0;
char c;
int judge = 0;
FILE* fp;
fp = fopen(filename, "r");
if (fp == NULL)
{
printf("打开文件失败或文件不存在");
return;
}
c = fgetc(fp);
while (c != EOF)
{
if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))
{
judge = 1; //记录前一个字符是不是字母
}
else
judge = 0;
c = fgetc(fp);
if (c == EOF) break;
if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')))
if (judge == 1)
wordnum++;
}
if (judge == 1)
wordnum++;
printf("词数:%d
", wordnum);
fclose(fp);
}
//统计空行和代码行 void countSline(char* filename) { int spaceline = 0; //空行 int codeline = 0; //代码行 char c; int jnull=1; //标志此行是不是空行 FILE* fp; fp = fopen(filename, "r"); if (fp == NULL) { printf("文件打开失败或文件不存在"); return; } do { c = fgetc(fp); if (c == ' ') { if (jnull == 1) spaceline++; else codeline++; jnull = 1; //每一行开始时默认为空行 } if (c != ' ' && c != ' ' && c != ' '&&c!=-1) //不是空格或换行或文件末尾,则不是空行 jnull = 0; } while (!feof(fp)); if (jnull == 1) spaceline++; //最后一行判断(没有换行符要独立判断) else codeline++; printf("代码行:%d ", codeline); printf("空行:%d ", spaceline); fclose(fp); }
//输入 目录时调用此函数处理目录下文件 void findFiles(char* Path, char* choose[], int argc) { intptr_t judgePath; //文件句柄,相当与文件指针fp,用于判断是否路径是否存在 _finddata_t File; int i = 1; FILE* fp; //用于判断是否是统计对象 char strfind[MAXSIZE]; //用于加通配符,寻找文件 char str[MAXSIZE]; //用于记录文件路径 strcpy(strfind, Path); strcat(strfind, "\"); strcat(strfind, "*.*"); // 在要遍历的目录后加上通配符 judgePath = _findfirst(strfind, &File); // 查找目录中的第一个文件 if (judgePath == -1) { printf("文件路径错误或不存在 "); return; } do { if (File.attrib & _A_SUBDIR && strcmp(File.name, ".") == 0 && strcmp(File.name, "..") == 0 ); else { strcpy(str, Path); strcat(str, "\"); strcat(str, File.name); if ((fp = fopen(str, "r")) != NULL) { printf("%s ", str); for (i = 1; i < argc - 1; i++) { if (strcmp(choose[i], "-c") == 0) countchar(str); if (strcmp(choose[i], "-l") == 0) countline(str); if (strcmp(choose[i], "-w") == 0) countword(str); } } } } while (_findnext(judgePath, &File) == 0); // 查找下一个文件 _findclose(judgePath); // 关闭句柄 }
int main(int argc, char* argv[]) { int i = 1; FILE* fp; fp = fopen(argv[argc - 1], "r"); if (fp == NULL) { findFiles(argv[argc - 1], argv, argc); } else { for (i = 1; i < argc - 1; i++) { if (strcmp(argv[i], "-c") == 0) countchar(argv[argc - 1]); if (strcmp(argv[i], "-l") == 0) countline(argv[argc - 1]); if (strcmp(argv[i], "-w") == 0) countword(argv[argc - 1]); if (strcmp(argv[i], "-a") == 0) { countSline(argv[argc - 1]); countnoteline(argv[argc - 1]); } } fclose(fp); } return 0; }
四. 运行结果
五. PSP
PSP2.1 |
Personal Software Process Stages |
预估耗时(分钟) |
实际耗时(分钟) |
Planning |
计划 |
60 |
60 |
· Estimate |
· 估计这个任务需要多少时间 |
300 |
400 |
Development |
开发 |
200 |
300 |
· Analysis |
· 需求分析 (包括学习新技术) |
100 |
200 |
· Design Spec |
· 生成设计文档 |
20 |
20 |
· Design Review |
· 设计复审 (和同事审核设计文档) |
15 |
15 |
· Coding Standard |
· 代码规范 (为目前的开发制定合适的规范) |
20 |
20 |
· Design |
· 具体设计 |
60 |
65 |
· Coding |
· 具体编码 |
120 |
200 |
· Code Review |
· 代码复审 |
20 |
20 |
· Test |
· 测试(自我测试,修改代码,提交修改) |
20 |
30 |
Reporting |
报告 |
30 |
50 |
· Test Report |
· 测试报告 |
20 |
30 |
· Size Measurement |
· 计算工作量 |
20 |
20 |
· Postmortem & Process Improvement Plan |
· 事后总结, 并提出过程改进计划 |
20 |
30 |
合计 |
1025 |
1460 |
六. 总结
刚看到这个题目的时候,我以为会很难,毕竟我对文件操作有了一些不好的印象,在理解过后,发现并不是很难。在写扩展功能的时候,因为对于题目要求没有理解正确,在写完功能后发现题目的要求并非如此,这给了我一个教训,以后需求分析要仔细。且自己对于函数的调用做得不是很好,在寻找目录下文件的函数中强行在进行一次指令判断,我觉得应该可以做的更好,但暂时没想出来。