我的項目(Word Count)

1、Github項目地址java

  https://github.com/AllForward/GP_Homework/tree/master/我的項目git


 

2、題目敘述github

  這個項目要求寫一個命令行程序,模仿已有wc.exe 的功能,並加以擴充,給出某程序設計語言源文件的字符數、單詞數和行數。實現一個統計程序,它能正確統計程序文件中的字符數、單詞數、行數,以及還具有其餘擴展功能,並可以快速地處理多個文件。正則表達式

  一、具體功能要求:
    程序處理用戶需求的模式爲:wc.exe [parameter] [file_name]編程

  二、基本功能列表:數組

  1. wc.exe -c file.c     //返回文件 file.c 的字符數
  2. wc.exe -w file.c    //返回文件 file.c 的詞的數目  
  3. wc.exe -l file.c      //返回文件 file.c 的行數

  三、擴展功能:ide

  1. -s   遞歸處理目錄下符合條件的文件。
  2. -a   返回更復雜的數據(代碼行 / 空行 / 註釋行)。

  四、高級功能:函數

     -x 參數。這個參數單獨使用。若是命令行有這個參數,則程序會顯示圖形界面,用戶能夠經過界面選取單個文件,程序就會顯示文件的字符數、行數等所有統計信息。學習

  五、注意事項:  測試

  1. 空行:本行所有是空格或格式控制字符,若是包括代碼,則只有不超過一個可顯示的字符,例如「{」。
  2. 代碼行:本行包括多於一個字符的代碼。
  3. 註釋行:本行不是代碼行,而且本行包括註釋。(注意:} //註釋 算做是註釋行)
  4. [file_name]: 文件或目錄名,能夠處理通常通配符。(通常通配符包括[],*,?,!,^)

3、解題思路

  一、首先題目要求說要對文本的內容進行一些統計,很顯然須要採用IO流來對文件進行讀取,以後對讀取的內容進行逐一統計,因爲本人對Java語言較爲熟悉,因此決定採用Java來進行編程;

    二、對於文件內容的統計,Java有對應的API能夠讀取每一行的內容,那麼我就對每次讀到的一行的內容進行分析統計,具體分析統計過程以下:每次將讀取的一行內容用字符串類型進行存儲;

  • 對於字符數,我先將每一行內容中的空格去掉,以後再獲取字符串的長度,這樣就能夠獲得每一行的字符數,最後將每一行的字符數相加就爲文件總的字符數;
  • 對於詞的數量,則是採用正則表達式的方式將每一行讀取到的內容,經過空格、分號、逗號、括號、點等標點符號進行分割成多個字符串,再經過正則將這多個字符串中非字母的字符去除,最終得到的字符串若不爲空就是一個單詞;(例子:讀取到的行內容爲:
    package com.company.FileStatistics; 那麼通過分割後的多個字符串分別爲:package,com,company,FileStatistics。因爲這些字符串中的不存在非字母的字符,因此最終結果就是這4個單詞;)最後將每一行的單詞數相加就爲文件總的單詞數;
  • 對於文件行數,那麼就是經過循環讀取文件的每一行,每讀一行總行數+1,直到讀完整個文件;
  • 對於遞歸處理目錄下符合條件的文件,則是經過文件名通配符對當前路徑下的全部文件進行掃描,一旦有符合的文件名,就將該文件加入到文件數組中,最後經過循環對文件數組的中每個文件進行統計分析;
  • 對於更復雜的數據(代碼行 / 空行 / 註釋行),首先是空行,那麼每當讀取到的內容爲空,或者改行只有一個字符,例如{,},那就是空行;註釋行則是要有/**/,//,我經過正則表達式的方式來判斷該行是否爲註釋行,其中須要注意到/**/形式的註釋能夠跨越多行,以及相似於"{ //"的註釋行;代碼行的話,則是須要該行在除去註釋內容的基礎上,剩餘的字符數多於1個;
  • 最後是GUI界面,我是經過Java的圖形庫JavaJW來實現的,主要是經過設置一個文件選擇框,來讓用戶選擇文件,以後返回文件的統計結果;

      


4、設計實現過程

 整個程序分紅三個類:

  主類:Main,普通及擴展功能HandleFile類以及GUI圖形界面類Swing

 

 整個程序分紅幾個主要函數:

  1. FileHandle(String[] args)接收控制檯輸入,同時判斷是否要進行GUI界面來統計,不是則調用ispermit函數判斷是否爲能夠進行統計的文件類型,是則調用change(String matches)對用戶輸入的文本通配符轉換成java正則表達式再調用getFiles()函數獲取符合條件的文件,是單個仍是多個;
  2. FileStatistics(File file, String type) 獲取用戶想要統計的類型,是空行仍是單詞數等等;
  3. SwingStatistics()經過GUI圖形界面進行統計的函數等等統計函數;

  流程圖以下:

    


 

 

5、代碼說明

1.Main類

package com.company; import com.company.FileStatistics.HandleFile; public class Main { public static void main(String[] args) { HandleFile.FileHandle(args); } }

2. HandleFile類

package com.company.FileStatistics; import java.io.*; import java.util.ArrayList; import java.util.List; /** * @description 文件基礎以及擴展功能實現 * @author guopei * @date 2020-03-13 10:55 */

public class HandleFile { //當前exe所在的文件路徑
    public static final String address = System.getProperty("exe.path"); public static Boolean isNotes = false; public static void FileHandle(String[] args) { // System.out.println("當前路徑爲:" + address);
        if (args[0].equals("-x")) { Swing.SwingStatistics(); return; } List<File> fileList = new ArrayList<File>(); //對發送過來的命令進行判斷
        if (isPermit(args[args.length - 1])) { File file = new File(address); args[args.length - 1] = change(args[args.length - 1]); if (file.isDirectory()) { //若是是文件夾,獲取當下的符合條件的文件
                getFiles(fileList, file.getPath(), args[args.length - 1]); } else { if (file.getName().matches(args[args.length - 1])) { fileList.add(file); } } //命令是遞歸查詢多個文件
            if (args[0].equals("-s")) { if (fileList.size() < 1) { System.out.println("查找不到符合條件的文件"); return; } //說明要統計多個文件
                for (File f : fileList) { String response = FileStatistics(f, args[1]); if ("不支持的命令格式".equals(response)) { System.out.println(response); break; } else if (response != null) { System.out.println(response); } } } //命令是查詢單個文件
            else { if (fileList.size() < 1) { System.out.println("查找不到符合條件的文件"); return; } else if (fileList.size() > 1) { System.out.println("查找到不止一個符合條件的文件,請加入-s命令來遞歸處理多個文件"); return; } System.out.println(FileStatistics(fileList.get(0), args[0])); } } else { System.out.println("文件格式不支持"); } } private static void getFiles(List<File> fileList, String path, String matches) { File file = new File(path); File[] files = file.listFiles(); for(File fileIndex:files){ //若是這個文件是目錄,則進行遞歸搜索
            if(fileIndex.isDirectory()){ getFiles(fileList, fileIndex.getPath(), matches); }else { //若是文件是符合匹配條件的文件,則將文件放入集合中
                if (fileIndex.getName().matches(matches)) { fileList.add(fileIndex); } } } } private static Integer WordStatistics(String content) { //統計詞的數目
        String copy = content; Integer num = 0; //統計詞的個數,將每一行數據切割成多個子字符串
        String[] strings = copy.split("[\\s+,\\.\n\\;\\(\\<\\[\\{]"); //對切割後的每一個字符串進行判斷
        for (int i = 0; i < strings.length; i++) { //將字符不是字母的去除
            strings[i] = strings[i].replaceAll("[^a-zA-Z]", ""); if (!strings[i].equals("")) { //若是不是空行,單詞數+1
                num++; } } return num; } //對文本通配符轉換成java的正則表達式
    public static String change(String matches) { String[] split = matches.split("\\."); matches = matches.replace(".", ""); matches = matches.replace(split[split.length - 1], "(." + split[split.length - 1] + ")"); matches = matches.replaceAll("\\?", ".{1}"); matches = matches.replaceAll("\\*", ".+"); matches = matches.replaceAll("!", "^"); return matches; } //統計更復雜的數據(代碼行 / 空行 / 註釋行)
    public static Integer[] LineStatistics(String content) { //順序爲:空行 / 註釋行
        Integer[] lines = {0, 0, 0}; //統計空行數
        if (content.equals("") || content.matches("[\\{\\}]")) { lines[0]++; } //統計註釋行
        else  if (content.matches("(.*)\\/\\/(.*)")) { lines[1]++; } else if (content.matches(".*\\/\\*.*\\*\\/")) { //說明使用了/**/的註釋形式
            lines[1]++; } else if (content.matches("(.*)\\/\\*(.*)")) { //說明使用了/*的註釋形式
            lines[1]++; isNotes = true; } else if (content.matches("(.*)\\*\\/(.*)")) { lines[1]++; isNotes = false; } else if (isNotes == true) { lines[1]++; } //統計代碼行
        if (content.matches(".{2,}") && isNotes == false && content.matches("(.*)[^\\\\/\\\\*](.*)")) { //去除掉註釋部分任然含有兩個及以上字符則就是代碼行
            String copy = content; copy = copy.replaceAll("\\/\\*.*\\*\\/", ""); copy = copy.replaceAll("\\/\\/(.*)", "").trim(); if (copy.matches(".{2,}")) { lines[2]++; } } return lines; } //正則判斷文件格式是否支持進行統計(符合的標準爲.c,.java,.cpp,.py,.txt)
    private static Boolean isPermit(String fileType) { if (fileType.matches(".+(.c|.java|.cpp|.py|.txt)$")) { return true; } return false; } /** * wc.exe -c file.c //返回文件 file.c 的字符數 * * wc.exe -w file.c //返回文件 file.c 的詞的數目 * * wc.exe -l file.c //返回文件 file.c 的行數 * 擴展功能: * -s 遞歸處理目錄下符合條件的文件。 * -a 返回更復雜的數據(代碼行 / 空行 / 註釋行)。 * @param file * @param type * @return
     */
    public static String FileStatistics(File file, String type) { //行數
        Integer line = 0; //單詞數
        Integer wordNum = 0; //字符數
        Integer charNum = 0; //空行數
        Integer nullLine = 0; //註釋行
        Integer notesLine = 0; //代碼行
        Integer codeLine = 0; try { //判斷文件類型是否符合
            if (!isPermit(file.getName())) { System.out.println("不支持的文件格式"); return "不支持的文件格式"; } BufferedReader bufferedReader = new BufferedReader(new FileReader(file)); String content = null; Boolean isNotes = false; while ((content = bufferedReader.readLine()) != null) { //去除字符串的首尾空格
                content = content.trim(); //System.out.println(content);
                switch (type) { case "-c": //返回文件的字符數 //將空格所有去除
                        content = content.replaceAll(" +", ""); charNum += content.length(); break; case "-w": //統計詞的數目
                        wordNum += WordStatistics(content); break; case "-a": Integer[] lines = LineStatistics(content); nullLine += lines[0]; notesLine += lines[1]; codeLine += lines[2]; break; case "-x": //統計所有信息
                        content = content.replaceAll(" +", ""); charNum += content.length(); wordNum += WordStatistics(content); Integer[] Lines = LineStatistics(content); nullLine += Lines[0]; notesLine += Lines[1]; codeLine += Lines[2]; break; case "-l": break; default: return "不支持的命令格式"; } //總行數
                line++; } switch (type) { case "-c": return file.getName() + "文件總字符數:" + charNum; case "-w": return file.getName() + "文件的單詞數:" + wordNum; case "-l": return file.getName() + "文件總行數:" + line; case "-a": return file.getName() + ":\r\n" +
                            "文件空行數:" + nullLine + "\r\n" +
                            "文件註釋行數:" + notesLine + "\r\n" +
                            "代碼行數:" + codeLine; case "-x": return file.getName() + ":\r\n" +
                            "文件總字符數:" + charNum + "\r\n" +
                            "文件的單詞數:" + wordNum + "\r\n" +
                            "文件總行數:" + line + "\r\n" +
                            "文件空行數:" + nullLine + "\r\n" +
                            "文件註釋行數:" + notesLine + "\r\n" +
                            "代碼行數:" + codeLine; default: return "不支持的命令格式"; } } catch (FileNotFoundException e) { System.out.println("該文件或文件名不存在"); } catch (IOException e) { System.out.println("文件讀取錯誤"); } return null; } }

3.Swing類

 

package com.company.FileStatistics; import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.File; /** * @description 圖形界面統計 * @author guopei * @date 2020-03-15 17:50 */
public class Swing { public static void SwingStatistics() { JFrame frame = new JFrame("文件選擇"); frame.setLayout(new FlowLayout()); JFileChooser chooser = new JFileChooser(); JButton bOpen = new JButton("打開文件"); frame.add(bOpen); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setSize(250, 150); frame.setLocationRelativeTo(null); frame.setVisible(true); bOpen.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { int returnVal = chooser.showOpenDialog(frame); File file = chooser.getSelectedFile(); if (returnVal == JFileChooser.APPROVE_OPTION) { JOptionPane.showMessageDialog(frame, "計劃打開文件:" + file.getAbsolutePath()); JOptionPane.showMessageDialog(frame, "文本內容統計:\n" + HandleFile.FileStatistics(file, "-x")); } } }); } }

 


6、測試運行

測試文件:

1.cpp(空文件) 

2.cpp(內容以下圖所示)

 

 

測試效果:

1.統計空文件1.cpp效果圖:(其中包括-w,-c以及-l命令)

 

 

2.統計非空文件2.cpp效果圖:(其中包括-a,-w,-c以及-l命令)

3.統計多個文件效果圖:(其中包括-a命令)

匹配全部.cpp文件

 

 

 匹配?.cpp文件

 

 

 匹配非1.cpp的文件

 

 

4. GUI界面統計效果圖:

輸入FileStatistics.exe -x後按回車便會有GUI圖形界面提示

 

 

 

 點擊"打開文件"按鈕後的效果以下:

 

 

從其中選擇一個符合統計條件的文件進行統計:

 

 

若選擇了不能統計的文件,則會有相應的提示,效果以下:(例如選擇了一個exe文件)


 

7、PSP表格

PSP2.1

Personal Software Process Stages

預估耗時(分鐘)

實際耗時(分鐘)

Planning

計劃

 15

 20

· Estimate

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

 180

 200

Development

開發

 130

 140

· Analysis

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

 10

 10

· Design Spec

· 生成設計文檔

 50

 60

· Design Review

· 設計複審 (和同事審覈設計文檔)

 10

 10

· Coding Standard

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

 8

 10

· Design

· 具體設計

 20

 25

· Coding

· 具體編碼

 130

 140

· Code Review

· 代碼複審

 20

 25

· Test

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

 30

 30

Reporting

報告

10

10 

· Test Report

· 測試報告

10 

10 

· Size Measurement

· 計算工做量

10 

20 

· Postmortem & Process Improvement Plan

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

10

 10

合計

 

 250

 260

 


 

8、項目小結
  本次項目讓我對於Java的IO流以及正則表達式的相關知識有了進一步地鞏固,同時經過PSP表格能夠發現,我的實際的開發時間是比預計的時間長的,主要的緣由是在一些知識點上還不夠熟悉,須要經過查閱相關資料以及筆記才能得以解決,同時在編寫代碼的時候.,有一些地方沒有注意,致使在測試的時候出現bug,所以返回去修改bug消耗的時間也是比較長的.總的來講就是分析問題須要再細緻一些,對於一些比較特殊的狀況要進行綜合考慮分析,還有就是知識點須要不斷地複習!

 

 

 

 

對文本通配符轉換成java的正則表達式
相關文章
相關標籤/搜索