JAVA实现WC.exe功能
項目要求
實現一個統計程序,它能正確統計程序文件中的字符數、單詞數、行數,以及還具備其他擴展功能,并能夠快速地處理多個文件。
具體功能要求:
程序處理用戶需求的模式為:
wc.exe [parameter] [file_name]
- 基本功能列表:
wc.exe -c file.c???? //返回文件 file.c 的字符數(實現)
wc.exe -w file.c??? //返回文件 file.c 的詞的數目?(實現)
wc.exe -l file.c????? //返回文件 file.c 的行數(實現)
- 擴展功能:
-s ? 遞歸處理目錄下符合條件的文件。(實現)
-a ? 返回更復雜的數據(代碼行 / 空行 / 注釋行)。(實現)
- 高級功能:
-x 參數。這個參數單獨使用。如果命令行有這個參數,則程序會顯示圖形界面,用戶可以通過界面選取單個文件,程序就會顯示文件的字符數、行數等全部統計信息。
(實現)
需求舉例:
wc.exe -s -a *.c?(實現)
返回當前目錄及子目錄中所有*.c 文件的代碼行數、空行數、注釋行數。
?Github項目地址:https://github.com/kvhong/JAVA-to-bulid-wc.exe
?解題思路
主函數思路:通過輸入的命令來判斷執行各個功能函數,將輸入的命令分割為兩部分,第一部分是指令,第二部分是文件路徑,用指令來調用各個功能函數,文件路徑則作為參數輸入到各個功能函數中實現功能。
功能函數的共同部分:通過傳入的文件路徑并用Buffer流讀取文件內容,對文件內容進行相應統計然后輸出結果,需實現文件不存在或者路徑輸入錯誤提示。
詞數統計函數:需要去除空行、各種符號,將獨立的詞統計出來;
字符統計函數:需要去除空行、空格,將其余的內容的每一個單元都示為一個字符統計出來;
行數統計函數:文件中全部行數除結尾空行不算外其他都統計;
空行:TAB、空格、回車形成的空行都算入;
注釋行:單獨存在//、/*、*/的算入注釋行;
代碼行:除了空行、注釋行外屬于代碼行;
幫助:將各種命令列出,以更好的幫助使用;
?用戶使用說明
-c 文件(須包含文件完整路徑) 統計程序文件中的字符數
-w 文件(須包含文件完整路徑) 統計程序文件中的單詞數
-l 文件(須包含文件完整路徑) 統計程序文件中的行數
-a 文件(須包含文件完整路徑) 統計程序文件中的空行數、代碼行數、注釋行數
-s-a 文件路徑或者文件夾路徑 遞歸統計程序文件中的空行數、代碼行數、注釋行數(-s 命令不可單獨使用)
? 幫助
end 結束程序
?
?遇到的問題及解決方法
一開始不知道如何對詞、字符進行有效的分割,然后在網上學習到可以用正則表達式進行分割:使用下面語句將數字和和中英文標點符號和中文都替換成空格,以通過空格分割出各個詞。
str.replaceAll("[\\p{Nd}\\u9fa5-\\uffe5\\p{Punct}\\s&&[^-]]", " ");使用下面的正則匹配器匹配注釋行和空行
Pattern nodeLinePattern = Pattern.compile("((//)|(/\\*+)|((^\\s)*\\*)|((^\\s)*\\*+/))+", Pattern.MULTILINE + Pattern.DOTALL); // 注釋匹配器(匹配單行、多行、文檔注釋) Pattern spaceLinePattern = Pattern.compile("^\\s*$"); // 空白行匹配器(匹配回車、tab鍵、空格)?設計及代碼
?該程序通過一個主函數文件和一個方法函數文件組成。主函數文件用于輸入參數并判斷所輸入的各種操作以調用方法函數。方法函數用于實現各種功能:
文件詞數統計函數:getwordnumber() 命令:-w ?文件路徑(須包含完整路徑)
?
//文件詞統計函數int getwordnumber(String filename) throws IOException {int num=0;String[] strword = null;File file = new File(filename);if(file.exists()) {//讀取文件FileReader fr = new FileReader(filename);br = new BufferedReader(fr);String line = null;StringBuffer sbf = new StringBuffer();while((line=br.readLine())!= null) {sbf.append(line);String str = sbf.toString();//正則表達式替換符號str = str.replaceAll("[\\p{Nd}\\u9fa5-\\uffe5\\p{Punct}\\s&&[^-]]", " ");//按空格將內容分割strword = str.split("\\s+");num=strword.length;}br.close();fr.close();}else {System.out.println("文件不存在,請重新輸入文件!");}return num;}?
文件字符數統計函數:getCharacternumber() 命令:-c ?文件路徑(須包含完整路徑)
?
//文件字符統計函數int getCharacternumber(String filename) throws IOException {int number = 0;String[] strword = null;File file = new File(filename);if(file.exists()) {//讀取文件FileReader fr = new FileReader(filename);br = new BufferedReader(fr);String line = null;String str=null;StringBuffer sbf = new StringBuffer();while((line=br.readLine())!= null) {sbf.append(line);str = sbf.toString();strword = str.split("\\s+");}for(int i=0;i<strword.length;i++) {Pattern pattern = Pattern.compile("[0-9a-zA-Z]*");Matcher matcher = pattern.matcher(strword[i]);if(matcher.find()) {number+=matcher.regionEnd();}}br.close();fr.close();}else {System.out.println("文件不存在,請重新輸入文件!");}return number;}?
文件行數統計函數:getlinenumber() 命令:-l ?文件路徑(須包含完整路徑)
?
//文件行數統計函數int getlinenumber(String filename) throws IOException {int linenum = 0;File file = new File(filename);if(file.exists()) {//讀取文件FileReader fr = new FileReader(filename);//讀取文件行數LineNumberReader lnr = new LineNumberReader(fr);while(lnr.readLine()!= null) {linenum=lnr.getLineNumber();}lnr.close();fr.close();}else {System.out.println("文件不存在,請重新輸入文件!");}return linenum;}?
統計文件或者文件夾中程序文件的空行、代碼行、注釋行,有遞歸文件目錄功能的函數,將遞歸功能一同實現在此函數中:diffline() 命令:-a 文件路徑或文件夾路徑/-s-a 文件路徑或文件夾路徑
?
//統計文件或者文件夾中程序文件的空行、代碼行、注釋行,有遞歸文件目錄功能int[] difflineGUI(File file) throws IOException {int spaceline = 0;int nodeline = 0;int codeline = 0;if (file == null || !file.exists()) {System.out.println(file + ",文件不存在!");}else {if (file.isDirectory()) {File[] files = file.listFiles(new FileFilter() {public boolean accept(File pathname) {return pathname.getName().endsWith(".java")|| pathname.isDirectory()||pathname.getName().endsWith(".c")||pathname.getName().endsWith(".cpp") ;}});//遞歸文件目錄for (File target : files) {diffline(target);}} else {BufferedReader bufr = null;// 將指定路徑的文件與字符流綁定bufr = new BufferedReader(new InputStreamReader(new FileInputStream(file)));// 定義匹配每一行的正則匹配器Pattern nodeLinePattern = Pattern.compile("((//)|(/\\*+)|((^\\s)*\\*)|((^\\s)*\\*+/))+", Pattern.MULTILINE + Pattern.DOTALL); // 注釋匹配器(匹配單行、多行、文檔注釋) Pattern spaceLinePattern = Pattern.compile("^\\s*$"); // 空白行匹配器(匹配回車、tab鍵、空格)// 遍歷文件中的每一行,并根據正則匹配的結果記錄每一行匹配的結果String line = null;while((line = bufr.readLine()) != null) {if (nodeLinePattern.matcher(line).find()) {nodeline ++;}else if (spaceLinePattern.matcher(line).find()) {spaceline ++;}else{codeline ++;} }}}int[] Sline= {spaceline,nodeline,codeline};return Sline;}用于wctest.java文件:
//統計文件或者文件夾中程序文件的空行、代碼行、注釋行,有遞歸文件目錄功能void diffline(File file) throws IOException {int spaceline = 0;int nodeline = 0;int codeline = 0;if (file == null || !file.exists()) {System.out.println(file + ",文件不存在!");}else {if (file.isDirectory()) {File[] files = file.listFiles(new FileFilter() {public boolean accept(File pathname) {return pathname.getName().endsWith(".java")|| pathname.isDirectory()||pathname.getName().endsWith(".c")||pathname.getName().endsWith(".cpp") ;}});//遞歸文件目錄for (File target : files) {diffline(target);}} else {System.out.println("文件名:"+file.getAbsolutePath());// 將指定路徑的文件與字符流綁定BufferedReader bufr = new BufferedReader(new InputStreamReader(new FileInputStream(file)));// 定義匹配每一行的正則匹配器Pattern nodeLinePattern = Pattern.compile("((//)|(/\\*+)|((^\\s)*\\*)|((^\\s)*\\*+/))+", Pattern.MULTILINE + Pattern.DOTALL); // 注釋匹配器(匹配單行、多行、文檔注釋) Pattern spaceLinePattern = Pattern.compile("^\\s*$"); // 空白行匹配器(匹配回車、tab鍵、空格)// 遍歷文件中的每一行,并根據正則匹配的結果記錄每一行匹配的結果String line = null;while((line = bufr.readLine()) != null) {if (nodeLinePattern.matcher(line).find()) {nodeline ++;}else if (spaceLinePattern.matcher(line).find()) {spaceline ++;}else{codeline ++;} }System.out.println("空行數:"+spaceline);System.out.println("注釋行數:"+nodeline);System.out.println("代碼行數:"+codeline);}}} 用于wctest.java的統計空行、注釋行、代碼行函數幫助函數:help() 命令:?
?
//幫助函數void help(){System.out.println("-c 文件(須包含文件完整路徑) 統計程序文件中的字符數");System.out.println("-w 文件(須包含文件完整路徑) 統計程序文件中的單詞數");System.out.println("-l 文件(須包含文件完整路徑) 統計程序文件中的行數");System.out.println("-a 文件(須包含文件完整路徑) 統計程序文件中的空行數、代碼行數、注釋行數");System.out.println("-s-a 文件路徑或者文件夾路徑 遞歸統計程序文件中的空行數、代碼行數、注釋行數");System.out.println("-x 打開用戶界面");System.out.println("? 幫助");System.out.println("end 結束程序");}主函數:wctest.java
?
package wc;import java.io.File; import java.io.IOException; import java.util.Scanner;public class wctest{private static Scanner scanner;public static void main(String[] args) throws IOException{String str = null;wcfunction wcf = new wcfunction();//循環詢問命令輸入while(true) {System.out.print("請輸入命令:");//命令輸入scanner = new Scanner(System.in);if(scanner.hasNext()) {str=scanner.nextLine();}//分割命令,第一個作為判斷第二個為文件路徑String[] strword = str.split(" ");if(strword.length==2) {if(strword[0].equals("-c")) {int chara=wcf.getCharacternumber(strword[1]);System.out.println("該文件的字符數:"+chara);}else if(strword[0].equals("-w")) {int word=wcf.getwordnumber(strword[1]);System.out.println("該文件的詞數:"+word);}else if(strword[0].equals("-l")) {int line=wcf.getlinenumber(strword[1]);System.out.println("該文件的行數:"+line);}else if(strword[0].equals("-a")) {File file = new File(strword[1]);int[] linenum=wcf.diffline(file);System.out.println("該文件的空行數:"+linenum[0]);System.out.println("該文件的注釋行數:"+linenum[1]);System.out.println("該文件的代碼行數:"+linenum[2]);}else if(strword[0].equals("-s-a")) {File file = new File(strword[1]);int[] linenum=wcf.diffline(file);System.out.println("該文件的空行數:"+linenum[0]);System.out.println("該文件的注釋行數:"+linenum[1]);System.out.println("該文件的代碼行數:"+linenum[2]);}}else {if(strword[0].equals("?")) {wcf.help();}else if(strword[0].equals("-x")) {wcGUI.main(null);}else if(strword[0].equals("end")) {break;}else {System.out.println("命令輸入錯誤,請重新輸入!");}}}} }用戶界面文件:wcGUI.java 命令:-x
package wc;import java.awt.EventQueue; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStreamReader; import javax.swing.JFrame; import javax.swing.JPanel; import java.awt.BorderLayout; import javax.swing.JScrollPane; import javax.swing.JButton; import javax.swing.JFileChooser; import javax.swing.JTextArea; import javax.swing.JTextField; import javax.swing.JLabel; import javax.swing.SwingConstants;public class wcGUI {private JFrame frmWc;private JTextField codenum;private JTextField wordnum;private JTextField linenum;private JTextField spaceline;private JTextField nodeline;private JTextField codeline;File file;wcfunction wcf=new wcfunction();/*** Launch the application.*/public static void main(String[] args) {EventQueue.invokeLater(new Runnable() {public void run() {try {wcGUI window = new wcGUI();window.frmWc.setVisible(true);} catch (Exception e) {e.printStackTrace();}}});}/*** Create the application.*/public wcGUI() {initialize();}/*** Initialize the contents of the frame.*/private void initialize() {frmWc = new JFrame();frmWc.setTitle("wc");frmWc.setResizable(false);frmWc.setBounds(280, 50, 800, 600);frmWc.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);JPanel panel = new JPanel();frmWc.getContentPane().add(panel, BorderLayout.CENTER);panel.setLayout(null);JScrollPane scrollPane = new JScrollPane();scrollPane.setBounds(291, 0, 493, 562);panel.add(scrollPane);JPanel panel_1 = new JPanel();scrollPane.setViewportView(panel_1);panel_1.setLayout(new BorderLayout(0, 0));JTextArea textArea = new JTextArea();textArea.setEditable(false);panel_1.add(textArea, BorderLayout.CENTER);JButton choosefile = new JButton("選擇文件");choosefile.setBounds(10, 32, 122, 23);panel.add(choosefile);JLabel filename = new JLabel("文件名:");filename.setBounds(10,70,80,23);panel.add(filename);JTextArea filepath = new JTextArea();filepath.setBounds(10, 95, 260, 40);filepath.setLineWrap(true);filepath.setWrapStyleWord(true); filepath.setEditable(false);panel.add(filepath);JButton code = new JButton("統計字符數");code.setBounds(10, 277, 100, 30);panel.add(code);JButton word = new JButton("統計詞數");word.setBounds(10, 317, 93, 30);panel.add(word);JButton line = new JButton("統計行數");line.setBounds(10, 357, 93, 30);panel.add(line);JButton diffline = new JButton("統計空行、注釋行、代碼行");diffline.setBounds(10, 397, 224, 30);panel.add(diffline);codenum = new JTextField();codenum.setBounds(120, 278, 93, 29);codenum.setEditable(false);panel.add(codenum);codenum.setColumns(10);wordnum = new JTextField();wordnum.setBounds(113, 318, 93, 30);wordnum.setEditable(false);panel.add(wordnum);wordnum.setColumns(10);linenum = new JTextField();linenum.setColumns(10);linenum.setBounds(113, 358, 93, 30);linenum.setEditable(false);panel.add(linenum);spaceline = new JTextField();spaceline.setColumns(10);spaceline.setBounds(70, 437, 93, 29);spaceline.setEditable(false);panel.add(spaceline);nodeline = new JTextField();nodeline.setColumns(10);nodeline.setBounds(70, 476, 93, 29);nodeline.setEditable(false);panel.add(nodeline);codeline = new JTextField();codeline.setColumns(10);codeline.setBounds(70, 515, 93, 30);codeline.setEditable(false);panel.add(codeline);JLabel label = new JLabel("空行");label.setHorizontalAlignment(SwingConstants.CENTER);label.setBounds(10, 437, 54, 29);panel.add(label);JLabel label_1 = new JLabel("注釋行");label_1.setHorizontalAlignment(SwingConstants.CENTER);label_1.setBounds(10, 476, 54, 29);panel.add(label_1);JLabel label_2 = new JLabel("代碼行");label_2.setHorizontalAlignment(SwingConstants.CENTER);label_2.setBounds(10, 515, 54, 30);panel.add(label_2);JLabel label_3 = new JLabel("個");label_3.setBounds(216, 277, 54, 30);panel.add(label_3);JLabel label_4 = new JLabel("個");label_4.setBounds(216, 317, 54, 30);panel.add(label_4);JLabel label_5 = new JLabel("行");label_5.setBounds(216, 357, 54, 30);panel.add(label_5);JLabel label_6 = new JLabel("行");label_6.setBounds(173, 437, 54, 30);panel.add(label_6);JLabel label_7 = new JLabel("行");label_7.setBounds(173, 476, 54, 30);panel.add(label_7);JLabel label_8 = new JLabel("行");label_8.setBounds(173, 515, 54, 30);panel.add(label_8);choosefile.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {JFileChooser filechooser = new JFileChooser(".");int result=filechooser.showOpenDialog(null);if(result == JFileChooser.APPROVE_OPTION){file=filechooser.getSelectedFile();if(file!=null) {if(textArea.getText()!=null) {textArea.setText("");}if(filepath.getText()!=null) {filepath.setText("");filepath.setText(file.getPath());}try {InputStreamReader read = new InputStreamReader(new FileInputStream(file), "GB2312");BufferedReader br = new BufferedReader(read);String line=null;while((line=br.readLine())!=null) {textArea.append(line+"\r\n");}br.close();} catch (IOException e1) {e1.printStackTrace();}}}}});code.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {if(file.exists()) {String filename = file.getAbsolutePath();try {int chara=wcf.getCharacternumber(filename);codenum.setText(chara+"");} catch (IOException e1) {// TODO Auto-generated catch block e1.printStackTrace();}}}});word.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {if(file.exists()) {String filename = file.getAbsolutePath();try {int word=wcf.getwordnumber(filename);wordnum.setText(word+"");} catch (IOException e1) {// TODO Auto-generated catch block e1.printStackTrace();}}}});line.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {if(file.exists()) {String filename = file.getAbsolutePath();try {int line=wcf.getlinenumber(filename);linenum.setText(line+"");} catch (IOException e1) {// TODO Auto-generated catch block e1.printStackTrace();}}}});diffline.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {if(file.exists()) {try {int[] line=wcf.difflineGUI(file);spaceline.setText(line[0]+"");nodeline.setText(line[1]+"");codeline.setText(line[2]+"");} catch (IOException e1) {// TODO Auto-generated catch block e1.printStackTrace();}}}});} } 用戶界面wcGUI.java測試
已將程序打包成wc.exe文件,放在Github項目中。可直接打開exe文件輸入命令和文件路徑直接使用,也可使用CMD命令行運行wc.exe再輸入命令和文件路徑使用。
CMD命令行使用:
exe直接使用:
用戶界面:
?
代碼覆蓋率
代碼覆蓋率:97.5%
PSP
?
| PSP2.1 | Personal Software Process Stages | 預估耗時(分鐘) | 實際耗時(分鐘) |
| Planning | 計劃 | 45 | 60 |
| · Estimate | · 估計這個任務需要多少時間 | 45 | 60 |
| Development | 開發 | 1290 | 1540 |
| · Analysis | · 需求分析 (包括學習新技術) | 80 | 120 |
| · Design Spec | · 生成設計文檔 | 40 | 60 |
| · Design Review | · 設計復審 (和同事審核設計文檔) | 40 | 40 |
| · Coding Standard | · 代碼規范 (為目前的開發制定合適的規范) | 30 | 30 |
| · Design | · 具體設計 | 120 | 160 |
| · Coding | · 具體編碼 | 780 | 920 |
| · Code Review | · 代碼復審 | 80 | 90 |
| · Test | · 測試(自我測試,修改代碼,提交修改) | 120 | 120 |
| Reporting | 報告 | 240 | 380 |
| · Test Report | · 測試報告 | 120 | 220 |
| · Size Measurement | · 計算工作量 | 30 | 40 |
| · Postmortem & Process Improvement Plan | · 事后總結, 并提出過程改進計劃 | 90 | 120 |
| ? | 合計 | 1575 | 1980 |
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
總結
先是從課堂上更加意識到制定設計流程的重要性,了解到計劃的設計不僅僅只存在于流程,對時間的規劃也是非常重要的。在編寫代碼過程中實質遇到的困難是在如何實現詞數的統計、正則表達式以及對文件目錄的遞歸實現。最后通過學習正則表達式實現了對詞數的統計,也進一步學習了正則表達式這一較為陌生的概念。也學會了一些新的插件和軟件的使用:Eclipse的EclEmma插件用于代碼覆蓋率的統計;Git Bash軟件對本地項目上傳到Github使用;exe4j軟件對JAVA項目進行EXE文件的打包使用。這次的項目作業對我來說是受益匪淺,對以后的項目實行有很大的幫助。
轉載于:https://www.cnblogs.com/K-mengmengpi/p/9614405.html
總結
以上是生活随笔為你收集整理的JAVA实现WC.exe功能的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: no acceptable C comp
- 下一篇: Mac Os 安装使用 itchat