个人项目WordCount(C++/QT)

个人项目WordCount(C++/QT)

GitHub项目地址:https://github.com/Nova-cjp/Word-Count

百度云链接:https://pan.baidu.com/s/1MSOXu0KbuUMJfJ8p8bwMwQ 提取码:jef2

已同步至个人博客:http://www.jpblog.xyz/Word-Count-WC-%E9%A1%B9%E7%9B%AE/

一、PSP表格

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

二、解题思路

2.1 基本需求分析
wc.exe -x //显示图形界面
wc.exe -s //递归处理目录下符合条件的文件(file.c /file.txt)。
wc.exe -a //返回更复杂的数据(代码行 / 空行 / 注释行)
wc.exe -l //返回文件 file.c /file.txt的行数
wc.exe -w //返回文件file.c /file.txt的词的数目
wc.exe -c //返回文件file.c /file.txt 的字符数

2.2 实现思路

因为在学校团队使用c++进行开发,对c++比较熟悉,所以选择使用c++进行开发。由于之前从来没有进行过GUI图形界面的开发,一开始并不打算实现高级功能。-l -s -a -w -c都是对文件内容进行处理计算,因此可以针对不同参数的选择对应不同的函数实现,并把函数和计算得出的文件内部属性(行数、字符数等)封装为一个类,属性设置为private,仅允许类函数访问,类函数设置为public,允许外部调用。在程序一开始实例化类对象,然后调用类函数进行处理,避免了多余参数的传递。

后来把基本功能、扩展功能实现完成后考虑进行图形界面的开发,才发现c++可用的图形库并不多(相比于java和python),而且考虑到用高级的图形库进行开发学习时间会较长。经过查阅资料和向同学了解,有三种方案看似可行,第一种是用easyxC++图形库开发,easyx面向初学者简单易上手,第二种是用python进行图形界面的开发(我不熟悉java),然后调用已经写好的C++程序,最后一种借用于Qt Creater中内置的Qt designer进行设计。经过考虑,我最后选择了Qt,easyx实现按键事件并没有对应的函数,虽然易上手但是难实现需求;python只能调用c语言程序,调用c++代码要进行复杂的转换和函数封装。而Qt正是为桌面应用而生,借助于布局界面自动生成部分图形代码,使开发周期大大缩短。

三、设计实现过程

3.1 类和函数

class Twc{
private:
  int num_of_characters;//字符数量
  int num_of_words;//词数
  int num_of_rows;//行数
  int num_of_codeLines;//代码行数
  int num_of_blankLines;//空白行数
  int num_of_commentLines;//注释行数
  struct Topt opt;
public:
  Twc(){
      num_of_characters=num_of_words=num_of_rows
=num_of_codeLines=num_of_blankLines=num_of_commentLines=0;
      opt.s=opt.c=opt.w=opt.l=opt.a=false;
  };
  void CalRows(FILE *fp);
  void CalCharacters(FILE*fp);
  void CalWords(FILE*fp);
  void CalCodelines(FILE*fp);
  void CalCommentlines(FILE*fp);
  void ListFiles(string path,string mode);
  void Work(char*filename);
  void Choose(int argc,char*argv[]);
};

3.2 系统流程图

四、核心代码说明

4.1 统计函数


bool IsCharacter(char ch){//用于判断除制表符、空格、回车之外可见的字符
  if(ch==' '||ch==' '||ch==' ')return false;
  else return true;
};

bool IsCharacter_(char ch){//用于判断英文字母
  if(ch>='0'&&ch<='9')return true;
  if(ch>='a'&&ch<='z')return true;
  if(ch>='A'&&ch<='Z')return true;
  return false;
};

void Twc::CalRows(FILE *fp){//计算行数
  char flag=0;int count=0;
  while(!feof(fp)){
      flag=fgetc(fp);
      if(flag==' ')
          count++;
  }
  num_of_rows=count+1;
  cout<<"the number of rows is "<<num_of_rows<<endl;
  rewind(fp);//重置文件指针到文件开头准备进行下一步操作
  return;
}

void Twc::CalCharacters(FILE *fp){//计算字符数
  char flag=0;int count=0;
  while(!feof(fp)){
      flag=fgetc(fp);
      if(IsCharacter(flag))
          count++;
  }
  num_of_characters=count-1;
  cout<<"the number of characters is "<<num_of_characters<<endl;
  rewind(fp);
  return;
}

void Twc::CalWords(FILE*fp){//计算词数
  char str[bufsize];
  int len;//每行的字符数
  int count=0;
  while(!feof(fp)){
      fgets(str,bufsize,fp);
      len=strlen(str);
      for(int i=0;i<len;i++)
      {
          if(IsCharacter_(str[i])){
              if(i==0||!IsCharacter_(str[i-1]))
                  count++;
          }
      }
  }
  num_of_words=count;
  cout<<"the number of words is "<<num_of_words<<endl;
  rewind(fp);
  return;
}

void Twc::CalCodelines(FILE*fp){//计算代码行数和空行
  char str[bufsize];
  int len;
  int show_code,code_line,blank_line;//每行可见字符数
  show_code=code_line=blank_line=0;
  while(!feof(fp)){
      fgets(str,bufsize,fp);
      len=strlen(str);
      for(int i=0;i<len;i++){
          if(IsCharacter(str[i]))
              show_code++;
      }
      if(show_code>1)
          code_line++;
      else
          blank_line++;
      show_code=0;//置零,计算下一行
  }
  num_of_codeLines=code_line;
  num_of_blankLines=blank_line;
  cout<<"the number of code lines is "<<num_of_codeLines<<endl;
  cout<<"the number of blank lines is "<<num_of_blankLines<<endl;
  rewind(fp);
  return;
}

void Twc::CalCommentlines(FILE*fp){//计算注释行
  char str[bufsize];
  int len;//每行的字符数
  int count=0;
  int show_comment=0;
  bool is_commentline= false;
  while(!feof(fp)){
      fgets(str,bufsize,fp);
      len=strlen(str);
      for(int i=0;i<len;i++){
          if(IsCharacter(str[i])){
              show_comment++;
              if(str[i]=='/'){
                  if(i+1<len&&str[i+1]=='/')
                      is_commentline= true;
                  break;
              }
              if(show_comment>1)
                  break;
          }
      }
      if(is_commentline==true)
          count++;
  }
  num_of_commentLines =count;
  cout<<"the number of comment lines is "<<num_of_commentLines<<endl;
  rewind(fp);
  return;
}

void Twc::Work(char *filename) {//运行函数
  if(opt.s== true){
      string mode = filename;
      string path=".\";
      ListFiles(path,mode);
      return;
  }
  FILE *fp=fopen(filename,"r");
  if(fp==NULL){
      cout<<"open file error!"<<endl;
      cout<<"Press any key to continue"<<endl;
      getchar();
      exit(0);
  }
  if(opt.l==true){
      CalRows(fp);
  }
  if(opt.c== true){
      CalCharacters(fp);
  }
  if(opt.a==true){
      CalCodelines(fp);
      CalCommentlines(fp);
  }
  if(opt.w== true){
      CalWords(fp);
  }
}

void Twc::ListFiles(string path,string mode){//递归处理目录下符合条件的文件
  _finddata_t file;
  intptr_t HANDLE;
  string Onepath = path + mode;
  HANDLE = _findfirst(Onepath.c_str(), &file);
  if (HANDLE == -1L)
  {
      cout << "can not match the folder path" << endl;
      system("pause");
  }
  do {
      //判断是否有子目录
      if (file.attrib & _A_SUBDIR)
      {
          //判断是否为"."当前目录,".."上一层目录
          if ((strcmp(file.name, ".") != 0) && (strcmp(file.name, "..") != 0))
          {
              string newPath = path +"\" + file.name;
              ListFiles(newPath,mode);
          }
      }
      else
      {
          cout << file.name << " " << endl;
          FILE *fp=fopen(&file.name[0],"r");
          if(fp==NULL){
              cout<<"open file error!"<<endl;
              cout<<"Press any key to continue"<<endl;
              getchar();
              exit(0);
          }
          if(opt.l==true){
              CalRows(fp);
          }
          if(opt.c== true){
              CalCharacters(fp);
          }
          if(opt.a==true){
              CalCodelines(fp);
              CalCommentlines(fp);
          }
          if(opt.w== true){
              CalWords(fp);
          }
          cout<<"------------------------------"<<endl;
      }
  } while (_findnext(HANDLE, &file) == 0);
  _findclose(HANDLE);
}

void Twc::Choose(int argc,char*argv[]){//参数选择
  for(int i=0;i<argc-1;i++){

      if(strcmp(argv[i],"-s")==0){
          opt.s=true;
      }
      if(strcmp(argv[i],"-c")==0){
          opt.c=true;
      }
      if(strcmp(argv[i],"-w")==0){
          opt.w=true;
      }
      if(strcmp(argv[i],"-l")==0){
          opt.l=true;
      }
      if(strcmp(argv[i],"-a")==0){
          opt.a=true;
      }
  }
}

4.2 Main函数,是否启用图形界面

int main(int argc, char *argv[])
{
  char filename[maxlen_filename];
  strcpy(filename,argv[argc-1]);
  Twc filefp;
  filefp.Choose(argc,argv);
  if(filefp.SomethingTrue()){
  filefp.Work(filename);
  return 0;
  }

  QApplication a(argc, argv);
  MainWindow w;
  w.setWindowTitle(QString("word count"));
  w.show();
  w.setAutoFillBackground(true);
  QPalette palette=w.palette();
  palette.setBrush(QPalette::Window,QBrush(QPixmap("C:\Users\24277
\Documents\WC\a.PNG").scaled(w.size()
,Qt::IgnoreAspectRatio,Qt::SmoothTransformation)));
  w.setPalette(palette);
  return a.exec();
}

五、测试运行

5.1 单文件测试

test.c

运行结果:

5.2 多文件测试

文件夹test

运行结果:

5.3 GUI测试

WC.exe -x打开GUI程序

输入框输入文件路径或点击选择文件按钮调出文件对话框选择文件

连续查询多个文件

六、项目小结

通过这次个人项目,我意识到软件工程学科的重要性(因为开始没有规划GUI扩展导致最后把项目的代码重写了一遍,分出了非GUI界面wc和GUI界面wc两个项目)。软件工程开始时的整体规划对项目的影响非常大,随着我们学习的深入,我们应该多花时间在分析规则上,从而减少开发、debug的时间。借助本次项目,我也学习到了图形界面的开发、main参数的使用、c与python之间的相互调用等,十分难得。

原文地址:https://www.cnblogs.com/JPblog/p/12563647.html