軟件工程實踐之詞頻統計


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

PSP表格:

PSP2.1 Personal 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++和數據結構。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM