wordcount
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)class
public class mainframe extends JFrame{
private JTextField textField;
private JPanel panel = new JPanel();
private JFileChooser fileChooser = new JFileChooser();
String selectedFile;
//主窗体设置
public mainframe() {
setTitle("wc.exe");
setBounds(400, 400, 600, 150);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final JLabel label = new JLabel();
label.setText("文件:");
panel.add(label);
textField = new JTextField();
textField.setColumns(20);
panel.add(textField);
JButton button = new JButton("选择文件");
JButton _char = new JButton("-c"); //返回文件 file.c 的字符数
JButton _word = new JButton("-w"); //返回文件 file.c 的词的数目
JButton _line = new JButton("-l"); //返回文件 file.c 的行数
JButton _other = new JButton("-a"); //返回更复杂的数据(代码行 / 空行 / 注释行)
_char.setMargin(new Insets(0,20,10,20));
_word.setMargin(new Insets(0,10,10,20));
_line.setMargin(new Insets(0,10,10,20));
_other.setMargin(new Insets(0,10,10,20));
JLabel labelin = new JLabel("递归遍历文件夹(-s)");
JTextField textField1 = new JTextField(16);
JButton inbutton = new JButton("确定");
Container contentPane = getContentPane();
contentPane.setLayout(new FlowLayout());
contentPane.add(labelin);
contentPane.add(textField1);
contentPane.add(inbutton);
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
int i = fileChooser.showOpenDialog(getContentPane());// 显示文件选择对话框
if (i == JFileChooser.APPROVE_OPTION) {
selectedFile = fileChooser.getSelectedFile().getAbsolutePath();// 获得选中的文件对象
String[] filehouzhui = selectedFile.split("\\.");
int Index = filehouzhui.length -1;
System.out.println(filehouzhui[Index]);
System.out.println(filehouzhui);
textField.setText(selectedFile);// 显示选中文件的名称
}
}
});
panel.add(button);
panel.add(_char);
panel.add(_word);
panel.add(_line);
panel.add(_other);
add(panel, BorderLayout.NORTH);
setVisible(true);
_char.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
int num = c(selectedFile); //返回文件 file.c 的字符数
JOptionPane.showMessageDialog(null, selectedFile+"字符数为"+num);
}
});
_word.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
int num = w(selectedFile); //返回文件 file.c 的词的数目
JOptionPane.showMessageDialog(null, selectedFile+"的词数为"+num);
}
});
_line.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
int num = l(selectedFile); //返回文件 file.c 的行数
JOptionPane.showMessageDialog(null, selectedFile+"的行数为"+num);
}
});
_other.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
int n1 = o(selectedFile,1); //空行
int n2 = o(selectedFile,2); //代码行
int n3 = o(selectedFile,3); //注释行
JOptionPane.showMessageDialog(null, selectedFile+"的空行数为"+n1+'\n'+selectedFile+"代码行数为"+n2+'\n'+selectedFile+"注释行数为"+n3);
}
});
inbutton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
String str = textField1.getText();
listFile(str); //递归遍历文件夹内所有文件
}
});
}
(2) 递归遍历文件夹功能
public static void listFile(String path)
{
File dir = new File(path);
File[] files=dir.listFiles(); //列出所有子文件
for(File file :files)
{
if(file.isFile())//是文件则输出文件名字
{
due(path+"\\"+file.getName());
System.out.println(path+"\\"+file.getName());
}else if(file.isDirectory())//是文件夹则输出文件夹的名字,并递归遍历
{
System.out.println(path+file.getName());
listFile(path);
}
}
}
(3)对文件夹内所有文件进行处理
public static void due(String file) { //-s 递归处理目录下符合条件的文件
int n1 = c(file);
int n2 = w(file);
int n3 = l(file);
int n4 = o(file,1);
int n5 = o(file,2);
int n6 = o(file,3);
JOptionPane.showMessageDialog(null, file+"的字符数为"+n1+"\n"+file+"的单词数为"+n2+"\n"+file+"的行数为"
+n3+"\n"+file+"的空行数为"+n4+"\n"+file+"的代码行数为"+n5+"\n"+file+"的注释行数为"+n6);
}
(4)-o功能的实现
public static int o(String file,int t) { //-a,t=1返回代码行 t=2返回空行 t=3返回注释行
int konghang = 0;
int daimahang = 0;
int zhushihang = 0;
int j = 0; //j是标记
String temp = null;
BufferedReader br = null;
try {
br = new BufferedReader(new FileReader(file));
while ((temp = br.readLine()) != null) {
temp = temp.replaceAll("\\{","").replaceAll("\\}","");
if(j==0) {
if((temp.trim().indexOf("/*")==0)) {zhushihang++;j=1;}
else if((temp.trim().indexOf("//")==0)) zhushihang++;
else if(temp.trim().length()>0) daimahang++;
else konghang++;
}
else{
zhushihang++;
if(temp.contains("*/")) j=0;
}
}
//br.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(t==1) return konghang;
else if(t==2) return daimahang;
else return zhushihang;
}
(5)-l功能的实现
public static int l(String file) { //返回文件 file.c 的行数
int linenum = 0;
BufferedReader br = null;
try {
br = new BufferedReader(new FileReader(file));
String temp = null;
while (((temp = br.readLine()) != null)) {
linenum++;
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return linenum;
}
(6)-w功能的实现
public static int w(String file) { //返回文件 file.c 的词的数目
int wordnum = 0;int i,j=0; //j是标记
BufferedReader br = null;
try {
br = new BufferedReader(new FileReader(file));
String temp = "";
while ((temp = br.readLine()) != null) {
char[] des = temp.trim().toCharArray();
for (i=0;i<des.length;i++) {
if (j==0&((des[i]>=48&des[i]<=57)|(des[i]>=65&des[i]<=90)|(des[i]>=97&des[i]<=122))) {wordnum++;j=1;}
if(des[i]<48|(des[i]>57&des[i]<65)|(des[i]>90&des[i]<97)|des[i]>122) j=0;
}}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return wordnum;
}
(7)-c功能的实现
public static int c(String file) { //返回文件 file.c 的字符数
int charnum = 0;int i;
BufferedReader br = null;
try {
br = new BufferedReader(new FileReader(file));
String temp = "";
while ((temp = br.readLine()) != null) {
char[] des = temp.trim().toCharArray();
for (i=0;i<des.length;i++)
if (des[i]!=' '&des[i]!='\t') charnum++;
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return charnum;
}
(8)主函数
public static void main(String[] args) {
mainframe test = new mainframe();
}
- 代码测试
- 对单个文件进行测试-c,-w,-l,-a
- 测试功能-s
8.项目总结
这次作业进一步锻炼我JAVA的编程能力,项目中的规范仍然不够,且仍然存在bug,例如:对文件夹的递归遍历处理得还不够好,以及还未解决注释算入字符数的问题,总体来说还不够熟练,很多知识都要上网查,做作业的时候遇到的问题有很多,花了很多的时间解决问题。利用PSP也提高了我的规划能力,提高我的效率。对于JAVA还要学习东西很多,我还必须进一步地提高自我,不断学习。

浙公网安备 33010602011771号