wordcount程序实现与测试

GitHub地址

https://github.com/jiaxuansun/wordcount

PSP表格

PSP PSP阶段 预估耗时(分钟) 实际耗时(分钟)
Planning 计划 10 5
·Estimate 估计这个任务需要多少时间 10 5
Development 开发 510 500
·Analysis 需求分析 (包括学习新技术) 40 30
·Design Spec 生成设计文档 20 20
·Design Review 设计复审 (和同事审核设计文档) 10 10
·Coding Standard 代码规范 (为目前的开发制定合适的规范) 10 10
·Design 具体设计 30 30
·Coding 具体编码 300 240
·Code Review 代码复审 40 40
·Test 测试(自我测试,修改代码,提交修改) 60 120
Reporting 报告 70 80
·Test Report 测试报告 30 40
·Size Measurement 计算工作量 10 10
·Postmortem & Process Improvement Plan 事后总结, 并提出过程改进计划 30 30
合计 590 585

解题思路

对整体程序的功能需求进行划分如下:

  • 参数分析功能:判断命令行的参数,保存所做的选项,并根据选项执行相应的命令,然后输出的结果

  • 查找文件功能:查找输入的文件需要支持如"*.c"等简单匹配符,在有-s选项的情况下,需要在当前目录下递归查找文件

  • 基本计数功能:实现课设基本功能要求的计算文件字符数、行数、单词数的功能

  • 代码计数功能:实现课设扩展功能要求的计算文件代码行数、空行数、注释行数的功能

根据功能复杂程度选择Python语言完成作业

程序设计实现

根据分析结果将代码分为如下几个模块:

  • 入口代码:设定所需要支持的参数内容
  • main函数:查找目录下所有的目标文件,对每一个文件调用基本功能函数和扩展功能函数,并将结果返回;若选择-s选项,则递归查找当前目录下的各个目录
  • wordcount函数:实现课设要求的基本功能
  • codecount函数:实现课设要求的扩展功能

代码说明

入口和标准库的参数解析对象初始化:

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="word count")
    parser.add_argument("-o", "--output", type=str, default="result.txt")
    parser.add_argument("-c", "--bytes", action="store_true")
    parser.add_argument("-w", "--words", action="store_true")
    parser.add_argument("-l", "--lines", action="store_true")
    parser.add_argument("-s", "--recursive", action="store_true")
    parser.add_argument("-a", "--code", action="store_true")
    parser.add_argument("-e", "--stoplist", type=str)
    parser.add_argument("filename", type=str)
    args = parser.parse_args()
    result = main(args, os.getcwd())
    print_result(args, result)

查找目录并根据不同的参数来调用不同的功能函数:

def main(args, rootpath):
    result = []
    filename = args.filename.replace("*", "\\w*")
    if args.recursive:
        for name in os.listdir(rootpath):
            path = os.path.join(rootpath, name)
            if os.path.isdir(path):
                result += main(args, path)
            elif re.findall(filename, name):
                fd = open(path)
                wc = wordcount(fd.read())
                if args.stoplist:
                    fd.seek(0)
                    content = fd.read()
                    stoplist = open(args.stoplist)
                    stopchars = stoplist.read().split()
                    count = 0
                    for c in stopchars:
                        count += len(re.findall(c, content))
                    r["words"] -= count
                    stoplist.close()
                if args.code:
                    fd.seek(0)
                    wc.update(codecount(fd))
                wc["filename"] = name
                result.append(wc)
                fd.close()
    else:
        for name in os.listdir(rootpath):
            path = os.path.join(rootpath, name)
            if os.path.isdir(path):
                pass
            elif re.findall(filename, name):
                fd = open(path)
                wc = wordcount(fd.read())
                if args.stoplist:
                    fd.seek(0)
                    content = fd.read()
                    stoplist = open(args.stoplist)
                    stopchars = stoplist.read().split()
                    count = 0
                    for c in stopchars:
                        count += len(re.findall(c, content))
                    r["words"] -= count
                    stoplist.close()
                if args.code:
                    fd.seek(0)
                    wc.update(codecount(fd))
                wc["filename"] = name
                result.append(wc)
                fd.close()

    return result

基本功能实现:

def wordcount(content):
    print(re.split(r"[\s,]+", content))
    result = {
        "words": len(re.split(r"[\s,]+", content))-1,  # 单词数
        "lines": len(content.split('\n'))-1,  # 行数
        "bytes": len(content)-1  # 字符数
    }

    return result

扩展功能实现

def codecount(fd):
    codelines = 0
    blanklines = 0
    commentlines = 0
    isComment = False
    isString = False
    isCode = False
    for line in fd.readlines():
        line = line.strip().replace('{', '').replace(
            '}', '').replace(';', '')  # 去掉{};以便计算空行
        if not isComment and not line:
            blanklines += 1
            continue
        if isComment:
            commentlines += 1
        elif line.replace('/', '').replace('*', ''):
            codelines += 1
        line = '\n'+line+'\n'
        for i in range(1, len(line)):
            if line[i] == '"' and line[i-1] != '\\':
                isString = not isString
            if not isString:
                if line[i] == '/' and line[i+1] == '/' and not isComment:
                    if not line[:i].split():
                        blanklines += 1
                    commentlines += 1
                    break
                if line[i] == '/' and line[i+1] == '*' and not isComment:
                    isComment = True
                    commentlines += 1
                    i += 1
                if line[i] == '*' and line[i+1] == '/':
                    isComment = False
                    i += 1

    result = {
        "codelines": codelines,
        "blanklines": blanklines,
        "commentlines": commentlines
    }

    return result

测试设计过程

如何设计测试用例

测试时应重点考虑边界值以及特殊情况,使测试用例最大程度覆盖代码。
思想是使每一个判断语句都执行一遍,实现条件覆盖,尽量让每一个判断语句在是与否的情况下都能执行一遍,实现语句覆盖。

哪些地方会导致程序高风险

当输入文件内容为空或输入大于文件内容的边界时会导致程序高风险

测试代码设计

  • test1.c
File write,name = new File(outputPath);
            writename.createNe|wFile();
            Buffe,redWriter out = new BufferedWrit,er(new FileWriter(writename));
            out.close();

测试字符数统计

  • test2.c
test()
{
File writename = new File(outputPath);
            writename.createNewFile();
codeLine */
            BufferedWriter out = new BufferedWriter(new FileWriter(writename));
    // note line
        out write(outputBuffer);
/* noteLine
/* noteLine
*/
/* noteLine */
/* noteLine
// noteLine
*/
        out.flush();
        out.close();
}
// noteLine
for(){}/* noteLine */

测试代码行数、注释行数、空行数统计

  • test3.c
test()
{
File writename = new File(outputPath);
            writename.createNewFile();
codeLine */
            BufferedWriter out = new BufferedWriter(new FileWriter(writename));
    // note line
        out write(outputBuffer);
/* noteLine
/* noteLine
*/
/* noteLine */
/* noteLine
// noteLine
*/
        out.flush();
        out.close();
} // noteLine
for(){
}/* noteLine */

测试单词数、行数统计

  • end.txt
for
new
out
  • 测试递归查找文件:文件夹test1,其中有一个test3.c文件,选择-s选项测试即可

-测试命令:
wordcount.exe
wordcount.exe -c test1.c
wordcount.exe -w test3.c
wordcount.exe -l test3.c
wordcount.exe -a test2.c -o testout1.txt
wordcount.exe -s -w test3.c
wordcount.exe -w -e end.txt test2.c
wordcount.exe -a -w -e end.txt test1.c
wordcount.exe -l -w -a -c test2.c -o testout2.txt
wordcount.exe -l -w -a -c -s test3.c -o testout2.txt

参考文献

  1. http://www.cnblogs.com/xinz/archive/2011/10/22/2220872.html
  2. http://www.ruanyifeng.com/blog/2016/01/commit_message_change_log.html
  3. http://www.cnblogs.com/xinz/archive/2011/11/20/2255830.html
posted @ 2018-03-20 22:55  James_Sun  阅读(346)  评论(2编辑  收藏  举报