Implementation of WC in JAVA

github地址

相关要求

  • 基本功能

    1. -c [文件名] 返回文件的字符数 (实现)
    2. -w [文件名] 返回文件的词的数目 (实现)
    3. -l [文件名] 返回文件的行数 (实现)
  • 扩展功能

    1. -s 递归处理目录下符合条件的文件。 (实现)
    2. -a 返回更复杂的数据(代码行/空行/注释行)(实现)
    3. 支持各种文件的通配符(*,?) (实现)
  • 高级功能

    1. 基本的Windows GUI 程序操作(实现)
    2. 支持通过图形界面选取文件(实现)
    3. 支持通过图形界面展现文件的信息(实现)

PSP

PSP2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟)
Planning 计划 30 35
· Estimate · 估计这个任务需要多少时间 30 35
Development 开发 1120 850
· Analysis · 需求分析 (包括学习新技术) 180 120
· Design Spec · 生成设计文档 120 60
· Design Review · 设计复审 (和同事审核设计文档) 60 40
· Coding Standard · 代码规范 (为目前的开发制定合适的规范) 100 60
· Design · 具体设计 180 120
· Coding · 具体编码 300 360
· Code Review · 代码复审 60 30
· Test · 测试(自我测试,修改代码,提交修改) 120 60
Reporting 报告 140 105
· Test Report · 测试报告 60 60
· Size Measurement · 计算工作量 60 30
· Postmortem & Process Improvement Plan · 事后总结, 并提出过程改进计划 20 15
合计 1260 955


设计说明

graph LR
A[MainWork] --> B(controller)
A[MainWork] --> C(UI)
B(controller) --> D(WordCounter)
B(controller) --> E(FileFinder)
C(UI) --> F(NewJFrame)

graph TB
A[WordCounter] --> B[CharacterSum]
A[WordCounter] --> c[Rows_Number]
A[WordCounter] --> d[word_cal]
A[WordCounter] --> e[isCodeLine]
A[WordCounter] --> f[isEmptyLine]
A[WordCounter] --> h[ScanFileinRecursion]
A[WordCounter] --> I[getRelatedFiles]
e[isCodeLine] --> g[isAnnotationLine]
f[isEmptyline] --> g[isAnnotationLine]

  • MainWork: 通过输入的参数来调用模块WordCounter中的方法实现基本要求和扩展要求,以及调用实现高级要求中的图形化界面

  • controller: 基本功能与扩展功能模块包

  • Word Counter:实现-c 统计文件字符数方法,实现-w 统计文件单词数方法,实现-l 统计文件行数,以及实现 -a中统计文件注释行,代码行,空行和-s的递归处理目录下文件的命令参数。

  • FileFinder:实现支持处理文件名通配符

  • UI(图形界面):NewJFrame 是为了实现处理-x参数传入时所设计的JAVA Swing图形化界面


解题思路与关键代码

代码

  1. -c 统计文件字符数

    解题思路 -FileReader读入文件,读入时计数器同时递增即可记录文件字符数目,单文件不存在计数器置为-1,与空文件区别开

      public static int CharacterSum(File file) throws IOException {
    int count_Char = 0;
    if(!file.exists())
    {
    count_Char = -1;
    return count_Char;
    }
    FileReader fr = new FileReader(file);
    while(fr.read()!=-1)
    {
    count_Char++;
    }
    return count_Char; }
  2. -l 统计文件行数

    解题思路 通过文件读入方式以字符缓冲输入流读入,缓冲字符,从而实现以行读取并计数器计算出行数,文件不存在时同上处理

     public static int Rows_number(File file) throws IOException {
    int count_Row = 0;
    if(!file.exists())
    {
    count_Row = -1;
    }
    else
    {
    FileReader fr = new FileReader(file);
    BufferedReader br = new BufferedReader(fr); String s = null;
    while((s=br.readLine())!=null)
    {
    count_Row++;
    }
    }
    return count_Row;
    }
  3. -w 统计文件单词数

    解题思路 学习了正则表达式,readLine每行读入文件与正则表达式匹配从而计算出单词数,文件不存在同上处理

    public static int word_cal(File file) throws IOException {
    int count_Word = 0;
    if(!file.exists())
    {
    count_Word = -1;
    }
    else
    {
    FileReader fr = new FileReader(file);
    BufferedReader br = new BufferedReader(fr);
    String s = null;
    while((s=br.readLine())!=null)
    {
    String reg = "\\d+.\\d+|\\w+";
    Matcher mat = Pattern.compile(reg).matcher(s);
    while(mat.find())
    {
    count_Word++;
    } }
    }
    return count_Word;
    }
  4. -a 统计文件空行,代码行,注释行

    解题思路与代码

    • 空行统计:根据需求,空行不得多于一个可显示字符,readLine读入文件每行字符串.trim()去掉空格和格式控制符,若字符串长度不大于1则空行计数器加一,文件不存在同上处理
    public static int isEmptyLine(File file) throws IOException {
    int count_EmptyLine = 0;
    if(!file.exists())
    {
    count_EmptyLine = -1;
    }
    else
    { FileReader fr = new FileReader(file);
    BufferedReader br = new BufferedReader(fr);
    String s = null;
    while((s=br.readLine())!=null)
    {
    if(s.trim().length()<=1){
    count_EmptyLine++;
    }
    } }
    return count_EmptyLine;
    }
    • 代码行统计:将文件readLine读入,每行字符串.trim()去掉空格,格式控制符之后通过正则表达式将注释符号//、/**/等匹配并删除,并对某些特殊情况进行处理,保留换行符,并append到StringBuffer中,最后将StringBuffer放入一个字符缓冲器当中并统计行数,即可得出代码行数目。文件不存在同上处理
     public static int isCodeLine(File file) throws IOException {
    int count_CodeLine = 0;
    if(!file.exists())
    {
    count_CodeLine = -1;
    }
    else {
    FileReader fr = new FileReader(file);
    BufferedReader br = new BufferedReader(fr);
    String s = null;
    Pattern p = Pattern.compile("\\/\\/[^\\n]*|\\/\\*([^\\*^\\/]*|[\\*^\\/*]*|[^\\**\\/]*)*\\*+\\/");
    String tmp = null;
    StringBuffer sb = new StringBuffer();
    String target = null;
    while ((s = br.readLine()) != null) {
    s = s.trim();
    int flag = 0;
    int pos = 0;
    for (int i = 1; i < s.length(); i++) {
    if ((i+1)<s.length()-1&&s.charAt(i) == '/' && (s.charAt(i + 1) == '/' || s.charAt(i + 1) == '*')) {
    pos = i; if(s.charAt(i)=='/'&&s.charAt(i+1)=='/')
    {
    sb.append(s,0,i);
    sb.append("\n");
    }
    else if(s.charAt(i+1)=='*'&& !s.substring(i).contains("*/"))
    {
    String t = (String) s.subSequence(0, i);
    sb.append(t);
    sb.append("\n");
    sb.append(s.substring(i));
    sb.append("\n");
    }
    else if(s.charAt(i+1)=='*'&& s.substring(i).contains("*/"))
    {
    Matcher m = p.matcher(s);
    tmp = m.replaceAll("");
    sb.append(tmp);
    sb.append("\n");
    flag = 1;
    break;
    }
    flag = 1; } }
    if (flag == 0) {
    if (s.length() > 1 && s.substring(0, 1).equals("*/")) { sb.append("*/");
    sb.append("\n");
    sb.append(s.substring(2));
    sb.append("\n");
    } else {
    sb.append(s);
    sb.append("\n"); }
    } }
    }
    br.close();
    target = sb.toString();
    Matcher mat = p.matcher(target);
    String res = null;
    res = mat.replaceAll("");
    BufferedReader context = new BufferedReader(new StringReader(res));
    while((tmp=context.readLine())!=null)
    { if(tmp.trim().length()>1)
    {
    count_CodeLine++;
    }
    } }
    return count_CodeLine;
    }
    • 注释行数目:通过以上对总行数,空行数,代码行数目的计算,则可以通过调用以上方法可得出注释行数目=总行数-空行数-代码行数目
            public static int isAnnotationLine(File file) throws IOException {
    int count_Annotation = 0;
    if(!file.exists())
    {
    count_Annotation = -1;
    }
    else
    {
    count_Annotation = Rows_number(file) - isEmptyLine(file) - isCodeLine(file);
    }
    return count_Annotation;
    }
  5. -s 递归处理目录下符合条件的文件。

    解题思路 将非根目录文件夹的文件路径名通过递归方法放入List中

     public static List<String> ScanFileInRecursion(File file)
    { if(!file.isDirectory())
    {
    System.out.println("非合法目录文件夹!请重新输入!");
    }
    else
    {
    File[] files = file.listFiles();
    for(int i=0;i<files.length;i++)
    {
    if(files[i].isDirectory())
    { ScanFileInRecursion(files[i]);
    }
    else
    {
    System.out.println(files[i].getAbsolutePath());
    filepath.add(files[i].getAbsolutePath());
    }
    } }
    return filepath;
    }
  6. 支持各种文件的通配符(*,?)

    解题思路 使用的是JDK 1.7,Files.walkFileTree,经过学习发现比File类的遍历效率要高很多,FileFinder类继承FileVisitor适配器SimpleFileVisitor,在编程设计中,Glob是一种模式,使用通配符来指定文件名,例如*.java,在Glob模式广泛使用通配符* 和 ?,通过files.walktreefile和NIO库中的glob模式,则可以遍历找出相关文件从而支持文件通配符

    FileFinder:

    public class FileFinder extends SimpleFileVisitor<Path> {
    private final PathMatcher matcher;
    private List<Path> matchedPaths = new ArrayList<Path>();
    private List<Path> matchedAbPaths = new ArrayList<Path>();
    FileFinder(String pattern)
    {
    matcher = FileSystems.getDefault().getPathMatcher("glob:"+ pattern);
    } void match(Path file)
    {
    Path name = file.getFileName();
    if(name!=null && matcher.matches(name)){
    matchedPaths.add(name); matchedAbPaths.add(file.toAbsolutePath());
    }
    }
    @Override
    public FileVisitResult visitFile(Path file,BasicFileAttributes attrs)
    {
    match(file);
    return CONTINUE;
    } @Override
    public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs)
    {
    match(dir);
    return CONTINUE;
    } @Override
    public FileVisitResult visitFileFailed(Path file, IOException exc)
    {
    System.err.println(exc);
    return CONTINUE;
    }
    public int getTotalMatches()
    {
    return matchedPaths.size();
    }
    public Collection<Path> getMatchedPaths()
    {
    return matchedPaths;
    }
    public List<Path> getMatchedAbPaths()
    {
    return matchedAbPaths;
    } }

    WordCounter的getRelatedFiles方法:

            public static List<Path> getRelateFiles(String filepath) throws IOException {
    FileFinder finder = new FileFinder(filepath);
    Files.walkFileTree(Paths.get(System.getProperty("user.dir")),finder); Collection<Path> Absolutematched = finder.getMatchedAbPaths();
    return (List<Path>) Absolutematched;
    }
  7. -x 图形化界面功能

    解题思路 根据Java的Swing设计界面,通过filechooser来选择文件进行wordcount功能演示。

    界面设计部分具体太多则不贴出,下面只贴按钮监听事件部分:

    private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) throws IOException, IOException {
    // TODO add your handling code here:
    jTextArea1.setText("");
    JFileChooser jfc=new JFileChooser();
    jfc.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES );
    jfc.showDialog(new JLabel(), "选择");
    File file=jfc.getSelectedFile();
    if(file.isDirectory()){
    System.out.println("文件夹:"+file.getAbsolutePath());
    }else if(file.isFile()){
    System.out.println("文件:"+file.getAbsolutePath());
    }
    System.out.println(jfc.getSelectedFile().getName());
    BufferedReader br = new BufferedReader(new FileReader(file));
    String s = null;
    while((s=br.readLine())!=null)
    {
    jTextArea1.append(s+"\n");
    } br.close();
    int char_count = CharacterSum(file);
    int word_count = word_cal(file);
    int line_cunt = Rows_number(file);
    int empty_line = isEmptyLine(file);
    int code_line = isCodeLine(file);
    int annotate_line = isAnnotationLine(file); if(char_count==-1||word_count==-1||line_cunt==-1||empty_line==-1||code_line==-1||annotate_line==-1)
    {
    chara.setText("字符数:0");
    jLabel2.setText("单词数:0");
    jLabel3.setText("总行数:0");
    jLabel4.setText("空行数:0");
    jLabel5.setText("注释行:0");
    jLabel6.setText("代码行:0");
    }
    else{
    chara.setText("字符数: "+char_count);
    jLabel2.setText("单词数: "+word_count);
    jLabel3.setText("总行数: "+line_cunt);
    jLabel4.setText("空行数: "+empty_line);
    jLabel5.setText("注释行: "+annotate_line);
    jLabel6.setText("代码行: "+code_line);
    } }

测试

命令行输入参数测试-c -w -l -a:

  • 一个典型源文件:

  • 一个空文件:

  • 只有一个字符的文件

  • 只有一个单词的文件

  • 只有一行的文件

测试-s:

测试 -x:

  • 测试典型源文件

  • 测试空文件

  • 测试只有一个字符的文件

  • 测试只有一个单词的文件



    *测试只有以行的文件

测试文本典型源文件:

#include<bits/stdc++.h>
using namespace std; typedef long long ll;
const int mod = 1e9+7;
void exgcd(ll a,ll b,ll &x,ll &y)
{
/*
欧几里得
*/
if(b==0)
{
x = 1;
y = 0;
return ;
}
ll x1,y1;
exgcd(b,a%b,x1,y1);
x = y1;
y = x1-(a/b)*y1;
}
int main()
{
//code here
ll n,m;
while(cin>>n>>m)
{
ll res = 1;
for(ll i=1;i<=n+m-4;i++)
res = (res*i)%mod;
for(ll i=1;i<=n-2;i++)
{
ll x,y;
exgcd(i,mod,x,y);
x = (x%mod+mod)%mod;
res = (res*x)%mod;
}
for(ll i=1;i<=m-2;i++)
{
ll x,y;
exgcd(i,mod,x,y);
x = (x%mod+mod)%mod;
res = (res*x)%mod;
}
res = (res%mod+mod)%mod;
cout<<res<<endl;
}
return 0;
}

代码覆盖率


小结

在设计完成该项目的时候收获很多,认识到对自己个人项目的设计的不足,包括时间的分配不科学,以及设计过程中对某些细节没有仔细考虑清楚,就开始着手程序,导致后面做了很多调整,让我觉得以后自身在学习开发时要多在前期设计下多点功夫。同时深刻了解到自己代码的不规范所带的问题。这次课程项目的开发用到了Java开发,过程中也学习到了不少新的东西,对以前学的东西有了进一步的了解,包括对如何通配符支持的研究和对正则表达式的深一步理解运用。希望自己能够在以后的项目设计和编写中通过学习和反省从而达到高效。

Implementation of WC in JAVA的更多相关文章

  1. WC.exe(Java实现)

    一.GitHub项目地址:https://github.com/nullcjm/mypage 二.项目相关要求: wc.exe 是一个常见的工具,它能统计文本文件的字符数.单词数和行数.这个项目要求写 ...

  2. 个人项目-WC(Java实现)

    一.Github项目地址: https://github.com/kestrelcjx/-WC-Java- 二.PSP表格 PSP2.1 Personal Software Process Stage ...

  3. 个人项目作业WC(JAVA)

    GitHub地址:https://github.com/1666403186/WC 一.题目描述 Word Count1. 实现一个简单而完整的软件工具(源程序特征统计程序).2. 进行单元测试.回归 ...

  4. 个人项目:wc程序(java)

    Github项目地址:https://github.com/jat0824/wc.git 项目相关要求 wc.exe 是一个常见的工具,它能统计文本文件的字符数.单词数和行数.这个项目要求写一个命令行 ...

  5. 个人项目-WC.exe (Java实现)

    一.Github项目地址:https://github.com/blanche789/wordCount/tree/master/src/main/java/com/blanche 二.PSP表格 P ...

  6. 个人项目wc(Java)

                                                      个人项目(Java) 一丶Github地址:https://github.com/SAH2019/S ...

  7. java实现wc

    github项目传送门:https://github.com/yanghuipeng/wc 项目要求 wc.exe 是一个常见的工具,它能统计文本文件的字符数.单词数和行数.这个项目要求写一个命令行程 ...

  8. JAVA实现WC.exe功能

    项目要求 实现一个统计程序,它能正确统计程序文件中的字符数.单词数.行数,以及还具备其他扩展功能,并能够快速地处理多个文件. 具体功能要求: 程序处理用户需求的模式为: wc.exe [paramet ...

  9. Java thread jargon

    In Java thread topic, the task to be executed and the thread to drive the task are two concepts shou ...

随机推荐

  1. Python中的类方法、实例方法、静态方法

    类方法 @classmethod 在python中使用较少,类方法传入的第一个参数是 cls,是类本身: 类方法可以通过类直接调用或者通过实例直接调用,但无论哪种调用方式,最左侧传入的参数一定是类本身 ...

  2. [规则原则定理]规则原则定理章2ACID原则

    ACID,指数据库事务正确执行的四个基本要素的缩写.包含:原子性(Atomicity).一致性(Consistency).隔离性(Isolation).持久性(Durability).一个支持事务(T ...

  3. Add to Array-Form of Integer LT989

    For a non-negative integer X, the array-form of X is an array of its digits in left to right order.  ...

  4. linux- Fedora25 下 解决anacondas3 与ibus冲突问题

    问题:当我们安装了anaconda3之后,会发现ibus-setup进不去. 原因: 是因为ibus-setup的python应该使用python2. 而当我们安装了anaconda3之后,调用pyt ...

  5. Asp.Net 启用全局IE兼容模式

    Asp.Net 启用全局IE兼容模式,不失为一个种简单最有效的解决方案: <system.webServer> <!-- 配置全局兼容 --> <httpProtocol ...

  6. 2017/2/13:springMVC拦截器的使用

    一.定义Interceptor实现类(主要是实现Handlerceptor接口) SpringMVC 中的Interceptor 拦截请求是通过HandlerInterceptor 来实现的.在Spr ...

  7. crud树型结构数据

    小型数据,比如标签,部门之类的,可以组织数据,成层状结构,一并返回前端,节省请求次数:但是大型数据,比如省市区等等联动,如果一并返回组织好的数据,查询量大,页面多次刷新,恶意请求,放入缓存还可以,其实 ...

  8. oracle 分组中排序(rank函数)

    需求: 查询每个供应商在每个类型产品销售的top50中有多少 分析: 1.查询,以指定字段(供应商.产品类型)分组,取每个分组的前50行,查看每个供应商的数量 2.使用rank函数给每个供应商.每个类 ...

  9. 2018.12.12 codeforces 931E. Game with String(概率dp)

    传送门 感觉这题难点在读懂题. 题目简述:给你一个字符串s,设将其向左平移k个单位之后的字符串为t,现在告诉你t的第一个字符,然后你可以另外得知t的任意一个字符,求用最优策略猜对k的概率. 解析: 预 ...

  10. C# 中使用面向切面编程(AOP)中实践代码整洁(转)

    出处:https://www.cnblogs.com/chenug/p/9848852.html 1. 前言 最近在看<架构整洁之道>一书,书中反复提到了面向对象编程的 SOLID 原则( ...