1、Github項目地址java
https://github.com/AllForward/GP_Homework/tree/master/我的項目git
2、題目敘述github
這個項目要求寫一個命令行程序,模仿已有wc.exe 的功能,並加以擴充,給出某程序設計語言源文件的字符數、單詞數和行數。實現一個統計程序,它能正確統計程序文件中的字符數、單詞數、行數,以及還具有其餘擴展功能,並可以快速地處理多個文件。正則表達式
一、具體功能要求:
程序處理用戶需求的模式爲:wc.exe [parameter] [file_name]編程
二、基本功能列表:數組
三、擴展功能:ide
四、高級功能:函數
-x 參數。這個參數單獨使用。若是命令行有這個參數,則程序會顯示圖形界面,用戶能夠經過界面選取單個文件,程序就會顯示文件的字符數、行數等所有統計信息。學習
五、注意事項: 測試
3、解題思路
一、首先題目要求說要對文本的內容進行一些統計,很顯然須要採用IO流來對文件進行讀取,以後對讀取的內容進行逐一統計,因爲本人對Java語言較爲熟悉,因此決定採用Java來進行編程;
二、對於文件內容的統計,Java有對應的API能夠讀取每一行的內容,那麼我就對每次讀到的一行的內容進行分析統計,具體分析統計過程以下:每次將讀取的一行內容用字符串類型進行存儲;
package com.company.FileStatistics; 那麼通過分割後的多個字符串分別爲:package,com,company,FileStatistics。因爲這些字符串中的不存在非字母的字符,因此最終結果就是這4個單詞;)最後將每一行的單詞數相加就爲文件總的單詞數;
4、設計實現過程
整個程序分紅三個類:
主類:Main,普通及擴展功能HandleFile類以及GUI圖形界面類Swing
整個程序分紅幾個主要函數:
流程圖以下:
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表格
|
8、項目小結
本次項目讓我對於Java的IO流以及正則表達式的相關知識有了進一步地鞏固,同時經過PSP表格能夠發現,我的實際的開發時間是比預計的時間長的,主要的緣由是在一些知識點上還不夠熟悉,須要經過查閱相關資料以及筆記才能得以解決,同時在編寫代碼的時候.,有一些地方沒有注意,致使在測試的時候出現bug,所以返回去修改bug消耗的時間也是比較長的.總的來講就是分析問題須要再細緻一些,對於一些比較特殊的狀況要進行綜合考慮分析,還有就是知識點須要不斷地複習!
對文本通配符轉換成java的正則表達式