1. 程式人生 > >第二周作業 WordCount

第二周作業 WordCount

新技術 center lsp class eth RM 獲取 取代 emp

https://github.com/HuangDongPeng/WordCount.git


1.1 PSP

PSP2.1

PSP階段

預估耗時

(分鐘)

實際耗時

(分鐘)

Planning

計劃

30

30

· Estimate

· 估計這個任務需要多少時間

5h

12h

Development

開發

2h

4h

· Analysis

· 需求分析 (包括學習新技術)

30min

30min

· Design Spec

· 生成設計文檔

-

-

· Design Review

· 設計復審 (和同事審核設計文檔)

-

-

· Coding Standard

· 代碼規範 (為目前的開發制定合適的規範)

5min  

5min

· Design

· 具體設計

10

0

· Coding

· 具體編碼

2h

3h

· Code Review

· 代碼復審

10

10

· Test

· 測試(自我測試,修改代碼,提交修改)

2h

3h

Reporting

報告

1h

1h

· Test Report

· 測試報告

· Size Measurement

· 計算工作量

· Postmortem & Process Improvement Plan

· 事後總結, 並提出過程改進計劃

20min

30min

合計

8h

12h







































2.1 WordCount需求說明

WordCount的需求可以概括為:對程序設計語言源文件統計字符數、單詞數、行數,統計結果以指定格式輸出到默認文件中,以及其他擴展功能,並能夠快速地處理多個文件。

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 //將結果輸出到指定文件outputFile.txt

wc.exe -s //遞歸處理目錄下符合條件的文件

wc.exe -a file.c //返回更復雜的數據(代碼行 / 空行 / 註釋行)

wc.exe -e stopList.txt // 停用詞表,統計文件單詞總數時,不統計該表中的單
2.2 解題思路及分析過程
功能實現
1.單詞統計
按字符流讀取文件,對每一個字符做判斷,如果不是換行符或空格則繼續往下讀取;當讀取到換行符或者空格是,將前面讀到的字符拼作一個單詞
,單詞計數加一:

while ((tempChar = reader.read()) != -1) {
            if ((tempChar >= 65 && tempChar <= 90) || (tempChar >= 97 && tempChar <= 122)) {
                isChar = true;
            } else {
                if (isChar) {
                    isChar = false;
                    wordCount++;
                }
                continue;
            }
        }



  



2.字符計數
每讀入一個字符,判斷是不是回車換行符,不是則字符計數器加一:

while ((tempChar = reader.read()) != -1) {
            //判斷是不是回車
            if (!(tempChar == 13 || tempChar == 10||tempChar==9))
                charCount++;
            character = (char) tempChar;
        }
        reader.close();

}

  

3.行數讀取
調用java API,統計計數

        reader = new BufferedReader(new FileReader(file));
        String tempString = null;
        int line = 0;
        while ((tempString = reader.readLine()) != null) {
            line++;
        }
        reader.close();return line;


4.遞歸獲取文件
獲取文件目錄,判斷是不是目錄,如果是目錄則遞歸獲取該目錄下的內容;如果符合要求的文件,則先將文件名存儲,與之後的執行一同進行

    File tmpFile = new File(dir);
    if (tmpFile.isDirectory()) {
        try {
            String[] fileNames = tmpFile.list();
            if (fileNames.length != 0) {
                for (String s : fileNames) {
                    String newPath = dir + "/" + s;
                    FindFile(newPath);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    } else {
        if (dir.contains(fomatName)) {
            int filePointIndex=dir.lastIndexOf(".");
            String rightFormatName=dir.substring(filePointIndex);
            if(rightFormatName.equals(fomatName))
                canBeFoundFile.add(dir);//存儲符合後綴文件
        }
    }

5.獲取不同類型的行數
獲取代碼行:非註釋、非空的都是代碼行
獲取註釋行:包含//或者包囊在 /* ..*/中的都是註釋行,按字符讀取,如果讀取到/*則進入註釋統計模式,直到讀取到*/才退出該模式繼續統計
獲取空行:不解釋

boolean isNote=false;
        reader = new BufferedReader(new FileReader(file));
        String tempString = null;
        int emptyLine = 0;
        int codeLine = 0;
        int noteLine = 0;
        while ((tempString = reader.readLine()) != null) {
            if(tempString.contains("/*")){
                isNote=true;
            }
            else if(tempString.contains("*/"))
            {
                isNote=false;
            }
            if (tempString.contains("//")||tempString.contains("*/")||isNote)
                noteLine++;
            else if (tempString.isEmpty() || IsEmpty(tempString)) {
                emptyLine++;
            } else
                codeLine++;
     

6.停用表功能
若存在於停用表中的單詞則統計單詞數時不計入統計。
先獲取停用表中的單詞,存儲與List,然後讀取指定文件單詞做判斷,若屬於停用表中的則單詞計數器不增加。

//讀取停用表內容      
while ((tempChar = reader.read()) != -1) { if ((tempChar >= 65 && tempChar <= 90) || (tempChar >= 97 && tempChar <= 122)) { isChar = true; sb.append((char) tempChar); } else { if (isChar) { wordTable.add(sb.toString()); sb = new StringBuilder(); isChar = false; } continue; } } if (isChar && sb.length() != 0) { wordTable.add(sb.toString()); }//讀取文件內容while ((tempChar = reader.read()) != -1) { if ((tempChar >= 65 && tempChar <= 90) || (tempChar >= 97 && tempChar <= 122)) { isChar = true; localSb.append((char) tempChar); } else { if (isChar) { if (!IsInTable(wordTable, localSb.toString())) { wordCount++; } localSb = new StringBuilder(); isChar = false; } continue; }

7.輸出文件
修改輸出文件名稱,不解釋


參數分析
在知道執行哪些命令前需要遍歷一遍輸入參數,存儲要執行的指令,在統一結合遞歸獲取文件等操作執行指令

//首先遍歷一邊參數,找出需要執行的指令   
for (int i = 0; i < inputArgs.length; i++) {
//如果使用了停用表指令,就獲取停用表名
if (inputArgs[i].contains("-e")) { isUseStopList = true; i++; stopListFileName = inputArgs[i]; } //是否需要重新定義輸出文件名並獲取輸出文件名 if (inputArgs[i].contains("-o")) { isOutPutFile = true; i++; outputFileName = inputArgs[i]; }
//是否遞歸搜索
if (inputArgs[i].contains("-s")) { isGetDirFiles = true; } }
//尋找目標文件,目標文件之前的都是執行參數
for (int i = 0; i < inputArgs.length; i++) { if (inputArgs[i].contains(".")) { fileNameIndex = i; filePath = inputArgs[i]; if (filePath.contains(".")) { int pointIndex = filePath.lastIndexOf("."); fomatName = filePath.substring(pointIndex); } break; } } if (!isGetDirFiles) { for (int i = 0; i < fileNameIndex; i++) { OrderJudge(inputArgs[i]); } } else { SetFileDir(inputArgs); FindFile(fileDir); for (String s : canBeFoundFile) { filePath = s; System.out.println(s); for (int i = 0; i < fileNameIndex; i++) { OrderJudge(inputArgs[i]); } } } //輸出文件 OutPutFile(outputFileName, sb); }



2.3測試
編寫測試,覆蓋每一個函數及功能,每一個的形參包括:讀取的文件名,預期的輸入;
每一個調用的輸出結果是:
測試名稱、預期結果、測試輸出結果、是否符合預期結果;

public boolean Test_CharCount(int expResult, String path) {
    return PrintErrorDetail(GetMethodName(), expResult, Main.ReadChar(path));
}
public boolean Test_WordCount(int expResult, String path) {
    return PrintErrorDetail(GetMethodName(), expResult, Main.ReadWord(path));
}
public boolean Test_LineCount(int expResult, String path) {
    return PrintErrorDetail(GetMethodName(), expResult, Main.ReadLine(path));
}
public boolean Test_ReadDiffLine(int emptyLine, int noteLine, int codeLine, String path) {
    int[] expResult = new int[3];
    expResult[0] = codeLine;
    expResult[1] = emptyLine;
    expResult[2] = noteLine;
    String[] lineNames = {"codeLine", "emptyLine", "noteLine"};
    int[] testResult = Main.GetDifferentLine(path);
    for (int i = 0; i < 3; i++) {
        PrintErrorDetail(GetMethodName() + " " + lineNames[i], expResult[i], testResult[i]);
        if (expResult[i] != testResult[i])
            return false;
    }
    return true;
}
public boolean Test_StopList(int expResult, String stoplistPath, String readFilePath) {
    int testResult = Main.StopWordTable(stoplistPath, readFilePath);
    return PrintErrorDetail(GetMethodName(), expResult, testResult);
}
public boolean Test_Recursion(int expFileCount, String path, String formateName) {
    Main.fomatName = formateName;
    return PrintErrorDetail(GetMethodName(), expFileCount, Main.FindFile(path));
}
public boolean Test_OutputFile(StringBuilder sb, String outputPath) {
    System.out.println("test: " + GetMethodName());
    if (Main.OutPutFile(outputPath, sb)) {
        System.out.println("out put file success");
        return true;
    }
    System.out.println("out put file failed");
    return false;
}
public boolean Test_Recursion_StopList(String formatName, String stopListName, int[] expCount) {
    Main.fomatName = formatName;
    Main.FindFile("./");
    boolean result = true;
    for (int i = 0; i < Main.canBeFoundFile.size(); i++) {
        if (!Test_StopList(expCount[i], stopListName, Main.canBeFoundFile.get(i))) {
            result = false;
        }
    }
    return result;
}
public boolean Test_Recusion_WordRead_OutputFile(String formatName, String outputFileName, int[] expResult) {
    Main.fomatName = formatName;
    Main.FindFile(Main.fileDir);
    boolean result = true;
    for (int i = 0; i < Main.canBeFoundFile.size(); i++) {
        if (expResult[i] != Main.ReadWord(Main.canBeFoundFile.get(i))) {
            result = false;
        }
    }
    if (result) {
        result = Main.OutPutFile(outputFileName, Main.sb);
    }
    return result;
}
 

第二周作業 WordCount