1. 程式人生 > >Word Count作業

Word Count作業

解析 pan pro lse str word got asf 結果

Word Count作業

一.個人Gitee地址:https://gitee.com/Changyu-Guo

二.項目簡介

該項目主要是模擬Linux上面的wc命令,基本要求如下:

命令格式:

wc.exe [para] <filename> [para] <filename> ... -o <filename>

功能:

wc.exe -c file.c:返回文件file.c的字符數

wc.exe -w file.c:返回文件file.c的單詞總數

wc.exe -l file.c:返回文件file.c的總行數

wc.exe -o outputFile.txt

:將結果輸出到指定文件

要求:

-o後面必須跟一個文件

-c -w -l可以同時出現

-c -w -l可以合並成 -wcl,即命令可以連寫

如果不指定輸出文件,則將結果默認保存在result.txt裏面

三.PSP2.1表格

PSP2.1PSP階段預估耗時(分鐘)實際耗時(分鐘)
Planning 計劃 5 5
· Estimate · 估計這個任務需要多少時間 5 5
Development 開發 340 635
· Analysis · 需求分析(包括學習新技術) 20 30
· Design Spec · 生成設計文檔 30 30
· Design Review · 設計復審(和同事審核設計文檔) 10 15
· Coding Standard · 代碼規範(為目前的開發制定合適的規範) 5 5
· Design · 具體設計 15 20
· Coding · 具體編碼 200 400
· Code Review · 代碼復審 40 30
· Test · 測試(自我測試,修改代碼,提交修改) 20 30
Reporting 報告 60 50
· Test Report · 測試報告 20 15
· Size Measurement · 計算工作量 10 5
· Postmortem & Process improvement Plan · 事後總結,並提出過程改進計劃 30 30
合計 405 690

四.解題思路

? 由於自己對C語言比較熟悉(主要是C語言編譯過後就是exe,其他語言還要打包,就直接用C語言寫了),因此選擇用C語言來實現這個項目。剛拿到題的時候仔細分析了一下,發現在功能上的要求不高,甚至不用校驗單詞的有效性,凡是以空格和逗號隔開的都算是單詞,因此第一次作業的難點應該在於命令行參數的解析上面。

? 接下來我用C語言寫了一個簡單的demo,嘗試著梳理一下程序構建思路,應該如何設計,模塊怎樣劃分。demo中所有的功能都在main函數裏面,沒有上傳到碼雲。

寫好demo後,大致整理了一下解題思路:

1.程序執行流程分析

? 根據項目的要求,該程序執行的大體流程為:首先用戶執行程序並附帶各種參數,程序首先要分析處理各種選項,校驗選項的有效性,並將各種參數和對應的文件聯系在一起,然後對不同的文件執行該文件對用的各種操作,然後將最終的結果一並保存在輸出文件中。

2.數據結構設計

? 根據對程序執行流程的分析,由於不同的文件對應著不同的操作,因此需要將文件名和其對應的操作綁定在一起,由此想到了用結構體保存一個文件的相關信息,然後使用鏈表將各個文件連起來。待命令處理完畢後,只需遍歷鏈表,即可對各個文件執行相應的操作。文件的結構體如下:

// 命令結構體
// 解析命令時存儲相關信息
struct Node
{
  bool _c;
  bool _w;
  bool _l;
  bool _hasFile;
  char inFile[100];
  int row;
  int character;
  int words;
  struct Node *next;
};

3.模塊劃分

根據程序的執行流程,可以將程序劃分為以下幾個模塊:

(1).主函數

主函數中主要是一些基本的處理和一些簡單的邏輯的處理,負責調用其他函數

(2).命令處理模塊

? 對於用戶輸入的命令的處理,有很多種辦法,其中最常用的就是遍歷數組,或者將輸入的命令編程字符串,然後解析字符串,我選擇的是將用戶輸入的各種選項和命令拼接成一個字符串,然後遍歷整個字符串,並做相應的分析。

(3).統計模塊

? 統計模塊主要就是對每個文件做相應的統計操作,包括對行數的統計,對單詞數的統計,對字符數的統計,每個功能寫在一個單獨的函數裏面。統計完字符後順便將數據寫入文件。

五.關鍵代碼分析

1.命令處理函數

  1 // 對用戶輸入的命令進行分析
  2 // 傳入的用戶輸入的命令的字符串,中間用空格隔開
  3 // 如果是-開頭的,則認為是選項
  4 // 如果檢測到-o,就立即讀取後面緊跟的輸出文件
  5 // 如果不是-開頭的,就認為是輸入文件
  6 
  7 // 第二個參數是一串文件的頭結點
  8 void analyseCommand(char commandStr[], struct Node *Head)
  9 {
 10   // 遍歷整個字符串
 11   initFileNode(Head);
 12   struct Node *cur;
 13   cur = Head;
 14   for (int i = 0;; i++)
 15   {
 16     // 讀出當前字符
 17     char c = commandStr[i];
 18     // 如果遍歷到了\0,說明字符串結束,則退出函數
 19     if (c == 0)
 20       return;
 21     // 如果c是-,則應該是一個選項
 22     if (c == -)
 23     {
 24       i++;
 25       // 讀取出-後面的字符,並做判斷
 26     read:
 27       c = commandStr[i];
 28       // 如果-後面是c,就將_c置為true
 29       if (c == c)
 30       {
 31         cur->_c = true;
 32         if (commandStr[++i] !=  )
 33         {
 34           goto read;
 35         }
 36         continue;
 37       }
 38       // 如果-後面是w,就將_w置為true
 39       else if (c == w)
 40       {
 41         cur->_w = true;
 42         if (commandStr[++i] !=  )
 43         {
 44           goto read;
 45         }
 46         continue;
 47       }
 48       // 如果-後面是l,就將_l置為true
 49       else if (c == l)
 50       {
 51         cur->_l = true;
 52         if (commandStr[++i] !=  )
 53         {
 54           goto read;
 55         }
 56         continue;
 57       }
 58       // 如果-後面是o,則後面緊跟的一個參數一定是filePath
 59       // 首先判斷後面是否有文件,如果有,就添加
 60       // 如果沒有,就報錯
 61       // 此時i的index是在選項上的
 62       else if (c == o)
 63       {
 64         i += 2; // 將i移動到
 65         char next = commandStr[i];
 66         if (next == - || next == 0)
 67         {
 68           printf("after -o must a para\n");
 69           exit(-1);
 70         }
 71         char path[100] = ""; // 用來存放輸出路徑
 72         for (int j = 0;; j++)
 73         {
 74           // 讀取出命令中的文件名中的每一個字符
 75           char ch = commandStr[i++];
 76 
 77           // 如果讀取到了0,就說明文件名讀取結束,就退出
 78           if (ch ==  )
 79           {
 80             break;
 81           }
 82           path[j] = ch;
 83         }
 84         memset(outFile, 0, sizeof(outFile));
 85         strcpy(outFile, path);
 86       }
 87       else
 88       {
 89         // 如果-後面什麽都沒有,就判定為錯誤
 90         printf("after - must a para\n");
 91         exit(-1);
 92       }
 93     }
 94     else
 95     {
 96       // 如果不是-,則判定為輸入文件
 97       // 此時i定位在輸入文件的第一個字符上
 98       char path[100] = "";
 99       for (int j = 0;; j++)
100       {
101         char ch = commandStr[i++];
102         if (ch ==  )
103         {
104           break;
105         }
106         path[j] = ch;
107       }
108       strcpy(cur->inFile, path);
109       cur->_hasFile = true;
110       struct Node *fileNode;
111       fileNode = (struct Node *)malloc(sizeof(struct Node));
112       initFileNode(fileNode);
113       cur->next = fileNode;
114       cur = fileNode;
115       i--;
116     }
117   }
118   // 檢測是否有輸入文件
119   // if (strlen(cur->inFile) == 0)
120   // {
121   //   printf("you do not have input file");
122   //   exit(-1);
123   // }
124 }

代碼分析:該函數是這次作業中最重要的一個函數,因此單獨拿出來說一下。

要點說明:

1.使用for循環遍歷整個字符串

2.遇到-之後就認為是一個選項,就緊接著讀取他的後一個字符,如果是有效參數,就記錄在當前文件的結構體中,否則報錯

3.如果是-o,則認為後面緊跟著一個輸出文件,不做文件名有效性檢驗,不做權限檢查

4.如果是普通字符開頭,則認為是輸入文件,不做文件名有效性檢查,不做權限檢查

5.根據規則,輸出文件應該放在該文件對應參數的後面

6.遍歷完畢之後,就將相關數據都保存在了文件的結構體中,並連接成了鏈表,返回後可進行後期相關操作。

六.測試設計

根據要求,根據如下條件設計測試:

是否有輸入

是否輸入-

-後是否有參數

是否統計行數

是否統計字符數

是否統計單詞數

是否支持命令連寫

是否支持多文件統計

是否有-o

-o後是否跟文件

根據以上條件,設計了如下批處理文件:

 1 .\wc.exe
 2 .\wc.exe -
 3 .\wc.exe -l
 4 .\wc.exe -c
 5 .\wc.exe -w
 6 .\wc.exe -lc
 7 .\wc.exe -lw
 8 .\wc.exe -cw
 9 .\wc.exe -lcw
10 .\wc.exe -lcw -o
11 .\wc.exe -lcw -o res.txt
12 .\wc.exe -lcw file1.c
13 .\wc.exe -lcw file1.c -o
14 .\wc.exe -lcw file1.c -o res.txt
15 .\wc.exe -lcw file1.c file2.c -o res.txt
16 .\wc.exe -lcw file1.c -lcw file2.c -o res.txt
17 .\wc.exe -lcw file1.c -o -lcw file2.c -o res.txt
18 PAUSE

測試結果如下:

技術分享圖片

技術分享圖片

文件輸出結果:

技術分享圖片

技術分享圖片

七.參考文獻

《構建之法--現代軟件工程》 --鄒新 [第三版]

博客園把我的格式變成了這個樣子

(哇的一聲就哭出來了)

Word Count作業