软件工程实践之词频统计

Github:https://github.com/1561602610/PersonProject-C2

PSP表格:

PSP2.1Personal Software Process Stages预估耗时(分钟)实际耗时(分钟)
Planning 计划    
• Estimate • 估计这个任务需要多少时间 720 1000
Development 开发 600 900
• Analysis • 需求分析 (包括学习新技术) 180 210
• Design Spec • 生成设计文档 40 50
• Design Review • 设计复审 30 60
• Coding Standard • 代码规范 (为目前的开发制定合适的规范) 10 30
• Design • 具体设计 30 50
• Coding • 具体编码 180 260
• Code Review • 代码复审 30 40
• Test • 测试(自我测试,修改代码,提交修改) 120 200
Reporting 报告 120 100
• Test Repor • 测试报告 30 20
• Size Measurement • 计算工作量 30 30
• Postmortem & Process Improvement Plan • 事后总结, 并提出过程改进计划 60 50
  合计 720 1000

需求分析

  1. 统计文件的字符数:

    • 只需要统计Ascii码,汉字不需考虑
    • 空格,水平制表符,换行符,均算字符
  2. 统计文件的单词总数,单词:至少以4个英文字母开头,跟上字母数字符号,单词以分隔符分割,不区分大小写。

    • 英文字母: A-Z,a-z
    • 字母数字符号:A-Z, a-z,0-9
    • 分割符:空格,非字母数字符号
    • 例:file123是一个单词, 123file不是一个单词。file,File和FILE是同一个单词
  3. 统计文件的有效行数:任何包含非空白字符的行,都需要统计。
  4. 统计文件中各单词的出现次数,最终只输出频率最高的10个。频率相同的单词,优先输出字典序靠前的单词。  

计算模块接口的设计与实现过程

实现字符计数:

#include "CharNum.h"
#include<fstream>
#include<iostream>
int CharNum(char * filename)
{
	int count = 0;
	char ch;
	FILE *file;
	fopen_s(&file,filename, "rt");
	for (; (ch=fgetc(file)) != EOF;) 
	{
		if (ch >= 0&&ch <= 255)
		count++;
	}
	fclose(file);
	return count;

	
}

  实现单词计数:

#include"WordNum.h"


int WordNum(char * filename)
{
    map<string, int> Word_Num_map;
    char ch;
    FILE *file;
    fopen_s(&file, filename, "rt");
    int flag = 0;            
    int count = 0;
    
    for (; (ch = fgetc(file)) != EOF;)
    {
        if ((ch >= 97 &&ch <= 122 )|| (ch >= 65 && ch <= 90))//英文字母
        {
            if (flag >= 0)flag++;
            if (flag < 0)flag--;
        }
        else if (ch >= 48 && ch <= 57)//数字
        {
            if (flag >= 4)flag++;
            else flag = -1;
        }
        else //非字母数字符号
        {
            if (flag >= 4) { count++; flag = 0; }
            else { flag = 0; }
        }
    }
    fclose(file);
    return count;
}

实现行数计数:

#include "LineNum.h"
int LineNum(char * filename)
{
    FILE *file;
    fopen_s(&file,filename, "rt");
    int count = 0;
    char ch;
    int flag = 0;
    for (; (ch = fgetc(file)) != EOF;)
    {
        if (ch == '\n')
        {
            if (flag > 0)count++;
            flag = 0;
        }
        else if (ch != ' '&&ch!='\t')
        {
            flag++;
        }
        
    }if (flag > 0)count++;
    fclose(file);
    return count;
}

实现词频统计及输出前十名:

#include"Word_Fre.h"
typedef pair<string, double> PAIR;
bool CmpByValue(const PAIR& lhs, const PAIR& rhs)
{
    return (lhs.second != rhs.second) ? lhs.second > rhs.second : lhs.first < rhs.first;
}
int Word_Fre(char * filename)
{
    map<string, int> Word_Num_map;
    char ch;
    string word;
    int flag = 0;
    FILE *file;
    fopen_s(&file, filename, "r");
    for (; (ch = fgetc(file)) != EOF;)
    {
        if ('A' <= ch && ch <= 'Z')
            ch = ch + 32;
        if (ch >= 'a' && ch <= 'z')//英文字母
        {
            if (flag >= 0) { flag++; word = word + ch; }
            if (flag < 0) { flag = 0; word = ""; }
        }
        else if (ch >= 48 && ch <= 57)//数字
        {
            if (flag >= 4) { flag++; word = word + ch; }
            else { flag = 0; word = ""; }
        }
        else //非字母数字符号
        {
            if (flag >= 4)
            {
                Word_Num_map[word]++;

                word = "";
                flag = 0;

            }
            else { flag = 0; word = ""; }
        }


    }
    if (flag >= 4)
    {
        Word_Num_map[word]++;
    }
    vector <PAIR> Word_Num_vec(Word_Num_map.begin(), Word_Num_map.end());
    sort(Word_Num_vec.begin(), Word_Num_vec.end(), CmpByValue);

    if (Word_Num_vec.size() < 10)
        for (int i = 0; i != Word_Num_vec.size(); ++i) {
            const char *ss = Word_Num_vec[i].first.c_str();
            cout << '<' << ss << '>' << ":" <<' '<< Word_Num_vec[i].second << endl;
        }
    else
        for (int i = 0; i != 10; ++i) {
            const char *ss = Word_Num_vec[i].first.c_str();
            cout << '<' << ss << '>' << ":" <<' '<< Word_Num_vec[i].second << endl;
        }
    return 0;
}

 

主要解题思路:

  设置标志位flag用于判断该位是否为单词的组成部分。

测试样例:

测试文本:

 

测试结果:

 

 

 

 

心路历程与收获:

  在努力完成这次实践的过程中,遇到了很多问题,首先的问题就是关于文件读取的问题,在遇到一个个问题的时候四处查找资料、请教同学,感觉确实有在学到东西。

  在解决词频统计这个问题上花了很长的时间,主要是用于思考记录单词及其频率的方法,后来查找以及问同学相关问题,知道了map这个东东还有一堆奇奇怪怪的函数,实在是后悔没好好学C++和数据结构。

 

posted @ 2018-09-12 22:51  黄锦峰  阅读(708)  评论(6编辑  收藏  举报