1.GitHub项目地址:https://github.com/qtqint/wordcount
2.题目描述
1. 实现一个简单而完整的软件工具(源程序特征统计程序)。
2. 进行单元测试、回归测试、效能测试,在实现上述程序的过程中使用相关的工具。
3. 进行个人软件过程(PSP)的实践,逐步记录自己在每个软件工程环节花费的时间。
3.项目要求
wc.exe 是一个常见的工具,它能统计文本文件的字符数、单词数和行数。这个项目要求写一个命令行程序,模仿已有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 返回更复杂的数据(代码行 / 空行 / 注释行)。
空行:本行全部是空格或格式控制字符,如果包括代码,则只有不超过一个可显示的字符,例如“{”。
代码行:本行包括多于一个字符的代码。
注释行:本行不是代码行,并且本行包括注释。一个有趣的例子是有些程序员会在单字符后面加注释:
} //注释
在这种情况下,这一行属于注释行。
[file_name]: 文件或目录名,可以处理一般通配符。
高级功能:
-x 参数。这个参数单独使用。如果命令行有这个参数,则程序会显示图形界面,用户可以通过界面选取单个文件,程序就会显示文件的字符数、行数等全部统计信息。
需求举例:
wc.exe -s -a *.c
返回当前目录及子目录中所有*.c 文件的代码行数、空行数、注释行数。
- 已实现功能:
基本功能:-c,-w,-l
扩展功能:-s,-a
- PSP
PSP2.1 |
Personal Software Process Stages |
预估耗时(分钟) |
实际耗时(分钟) |
Planning |
计划 |
30 |
20 |
· Estimate |
· 估计这个任务需要多少时间 |
12*60 |
15*60 |
Development |
开发 |
8*60 |
11*60 |
· Analysis |
· 需求分析 (包括学习新技术) |
4*60 |
4*60 |
· Design Spec |
· 生成设计文档 |
|
|
· Design Review |
· 设计复审 (和同事审核设计文档) |
|
|
· Coding Standard |
· 代码规范 (为目前的开发制定合适的规范) |
|
|
· Design |
· 具体设计 |
30 |
30 |
· Coding |
· 具体编码 |
6.5*60 |
9.5*60 |
· Code Review |
· 代码复审 |
15 |
15 |
· Test |
· 测试(自我测试,修改代码,提交修改) |
1*60 |
3*60 |
Reporting |
报告 |
|
|
· Test Report |
· 测试报告 |
30 |
30 |
· Size Measurement |
· 计算工作量 |
10 |
15 |
· Postmortem & Process Improvement Plan |
· 事后总结, 并提出过程改进计划 |
10 |
20 |
合计 |
|
12*60 |
15*60 |
1.设计思路:
先根据需求写好窗体并添加按钮,再依次实现功能。
2.代码实现:
1 import java.awt.*; 2 import java.awt.event.*; 3 import java.io.*; 4 import javax.swing.*; 5 6 public class mainframe extends JFrame{ 7 private JTextField textField; 8 private JPanel panel = new JPanel(); 9 private JFileChooser fileChooser = new JFileChooser(); 10 String selectedFile; 11 //主窗体设置 12 public mainframe() { 13 setTitle("wc.exe"); 14 setBounds(400, 400, 600, 150); 15 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 16 final JLabel label = new JLabel(); 17 label.setText("文件:"); 18 panel.add(label); 19 textField = new JTextField(); 20 textField.setColumns(20); 21 panel.add(textField); 22 23 JButton button = new JButton("选择文件"); 24 JButton _char = new JButton("-c"); //返回文件 file.c 的字符数 25 JButton _word = new JButton("-w"); //返回文件 file.c 的词的数目 26 JButton _line = new JButton("-l"); //返回文件 file.c 的行数 27 JButton _other = new JButton("-a"); //返回更复杂的数据(代码行 / 空行 / 注释行) 28 29 _char.setMargin(new Insets(0,20,10,20)); 30 _word.setMargin(new Insets(0,10,10,20)); 31 _line.setMargin(new Insets(0,10,10,20)); 32 _other.setMargin(new Insets(0,10,10,20)); 33 34 35 JLabel labelin = new JLabel("递归遍历文件夹(-s)"); 36 JTextField textField1 = new JTextField(16); 37 JButton inbutton = new JButton("确定"); 38 Container contentPane = getContentPane(); 39 contentPane.setLayout(new FlowLayout()); 40 contentPane.add(labelin); 41 contentPane.add(textField1); 42 contentPane.add(inbutton); 43 44 button.addActionListener(new ActionListener() { 45 public void actionPerformed(ActionEvent e) { 46 int i = fileChooser.showOpenDialog(getContentPane());// 显示文件选择对话框 47 if (i == JFileChooser.APPROVE_OPTION) { 48 selectedFile = fileChooser.getSelectedFile().getAbsolutePath();// 获得选中的文件对象 49 String[] filehouzhui = selectedFile.split("\\."); 50 int Index = filehouzhui.length -1; 51 System.out.println(filehouzhui[Index]); 52 System.out.println(filehouzhui); 53 textField.setText(selectedFile);// 显示选中文件的名称 54 } 55 } 56 }); 57 panel.add(button); 58 panel.add(_char); 59 panel.add(_word); 60 panel.add(_line); 61 panel.add(_other); 62 63 add(panel, BorderLayout.NORTH); 64 setVisible(true); 65 66 _char.addActionListener(new ActionListener() { 67 public void actionPerformed(ActionEvent e) { 68 int num = c(selectedFile); //返回文件 file.c 的字符数 69 JOptionPane.showMessageDialog(null, selectedFile+"字符数为"+num); 70 } 71 }); 72 _word.addActionListener(new ActionListener() { 73 public void actionPerformed(ActionEvent e) { 74 int num = w(selectedFile); //返回文件 file.c 的词的数目 75 JOptionPane.showMessageDialog(null, selectedFile+"的词数为"+num); 76 } 77 }); 78 _line.addActionListener(new ActionListener() { 79 public void actionPerformed(ActionEvent e) { 80 int num = l(selectedFile); //返回文件 file.c 的行数 81 JOptionPane.showMessageDialog(null, selectedFile+"的行数为"+num); 82 } 83 }); 84 _other.addActionListener(new ActionListener() { 85 public void actionPerformed(ActionEvent e) { 86 int n1 = o(selectedFile,1); //空行 87 int n2 = o(selectedFile,2); //代码行 88 int n3 = o(selectedFile,3); //注释行 89 JOptionPane.showMessageDialog(null, selectedFile+"的空行数为"+n1+'\n'+selectedFile+"代码行数为"+n2+'\n'+selectedFile+"注释行数为"+n3); 90 } 91 }); 92 inbutton.addActionListener(new ActionListener() { 93 public void actionPerformed(ActionEvent e) { 94 String str = textField1.getText(); 95 listFile(str); //递归遍历文件夹内所有文件 96 } 97 }); 98 } 99 100 101 public static void listFile(String path) 102 { 103 File dir = new File(path); 104 File[] files=dir.listFiles(); //列出所有子文件 105 for(File file :files) 106 { 107 if(file.isFile())//是文件则输出文件名字 108 { 109 due(path+"\\"+file.getName()); 110 System.out.println(path+"\\"+file.getName()); 111 }else if(file.isDirectory())//是文件夹则输出文件夹的名字,并递归遍历 112 { 113 System.out.println(path+file.getName()); 114 listFile(path); 115 } 116 } 117 } 118 public static void due(String file) { //-s 递归处理目录下符合条件的文件 119 int n1 = c(file); 120 int n2 = w(file); 121 int n3 = l(file); 122 int n4 = o(file,1); 123 int n5 = o(file,2); 124 int n6 = o(file,3); 125 JOptionPane.showMessageDialog(null, file+"的字符数为"+n1+"\n"+file+"的单词数为"+n2+"\n"+file+"的行数为" 126 +n3+"\n"+file+"的空行数为"+n4+"\n"+file+"的代码行数为"+n5+"\n"+file+"的注释行数为"+n6); 127 } 128 public static int o(String file,int t) { //-a,t=1返回代码行 t=2返回空行 t=3返回注释行 129 int konghang = 0; 130 int daimahang = 0; 131 int zhushihang = 0; 132 int j = 0; //j是标记 133 String temp = null; 134 BufferedReader br = null; 135 try { 136 br = new BufferedReader(new FileReader(file)); 137 while ((temp = br.readLine()) != null) { 138 temp = temp.replaceAll("\\{","").replaceAll("\\}",""); 139 if(j==0) { 140 if((temp.trim().indexOf("/*")==0)) {zhushihang++;j=1;} 141 else if((temp.trim().indexOf("//")==0)) zhushihang++; 142 else if(temp.trim().length()>0) daimahang++; 143 else konghang++; 144 } 145 else{ 146 zhushihang++; 147 if(temp.contains("*/")) j=0; 148 } 149 } 150 //br.close(); 151 } catch (FileNotFoundException e) { 152 e.printStackTrace(); 153 } catch (IOException e) { 154 e.printStackTrace(); 155 } finally { 156 try { 157 br.close(); 158 } catch (IOException e) { 159 e.printStackTrace(); 160 } 161 } 162 if(t==1) return konghang; 163 else if(t==2) return daimahang; 164 else return zhushihang; 165 } 166 public static int l(String file) { //返回文件 file.c 的行数 167 int linenum = 0; 168 BufferedReader br = null; 169 try { 170 br = new BufferedReader(new FileReader(file)); 171 String temp = null; 172 while (((temp = br.readLine()) != null)) { 173 linenum++; 174 } 175 } catch (FileNotFoundException e) { 176 e.printStackTrace(); 177 } catch (IOException e) { 178 e.printStackTrace(); 179 } finally { 180 try { 181 br.close(); 182 } catch (IOException e) { 183 e.printStackTrace(); 184 } 185 } 186 return linenum; 187 } 188 public static int w(String file) { //返回文件 file.c 的词的数目 189 int wordnum = 0;int i,j=0; //j是标记 190 BufferedReader br = null; 191 try { 192 br = new BufferedReader(new FileReader(file)); 193 String temp = ""; 194 while ((temp = br.readLine()) != null) { 195 char[] des = temp.trim().toCharArray(); 196 for (i=0;i) { 197 if (j==0&((des[i]>=48&des[i]<=57)|(des[i]>=65&des[i]<=90)|(des[i]>=97&des[i]<=122))) {wordnum++;j=1;} 198 if(des[i]<48|(des[i]>57&des[i]<65)|(des[i]>90&des[i]<97)|des[i]>122) j=0; 199 }} 200 } catch (FileNotFoundException e) { 201 e.printStackTrace(); 202 } catch (IOException e) { 203 e.printStackTrace(); 204 } finally { 205 try { 206 br.close(); 207 } catch (IOException e) { 208 e.printStackTrace(); 209 } 210 } 211 return wordnum; 212 } 213 public static int c(String file) { //返回文件 file.c 的字符数 214 int charnum = 0;int i; 215 BufferedReader br = null; 216 try { 217 br = new BufferedReader(new FileReader(file)); 218 String temp = ""; 219 while ((temp = br.readLine()) != null) { 220 char[] des = temp.trim().toCharArray(); 221 for (i=0;i ) 222 if (des[i]!=' '&des[i]!='\t') charnum++; 223 } 224 } catch (FileNotFoundException e) { 225 e.printStackTrace(); 226 } catch (IOException e) { 227 e.printStackTrace(); 228 } finally { 229 try { 230 br.close(); 231 } catch (IOException e) { 232 e.printStackTrace(); 233 } 234 } 235 return charnum; 236 } 237 238 public static void main(String[] args) { 239 mainframe test = new mainframe(); 240 } 241 }
3.代码测试
对单个文件进行测试-c,-w,-l,-a
测试功能-s
4.项目总结
这次作业进一步锻炼我JAVA的编程能力,项目中的规范仍然不够,且仍然存在bug,例如:对文件夹的递归遍历处理得还不够好,以及还未解决注释算入字符数的问题,总体来说还不够熟练,很多知识都要上网查,做作业的时候遇到的问题有很多,花了很多的时间解决问题。利用PSP也提高了我的规划能力,提高我的效率。对于JAVA还要学习东西很多,我还必须进一步地提高自我,不断学习。
5.参考资料
java做一个简单的文本输入框https://www.pianshen.com/article/2855335832/
java文件夹递归遍历https://www.cnblogs.com/invban/p/7975529.html
java文件选择https://blog.csdn.net/qq_36761831/article/details/81489699