wordcount程序实现与测试

GitHub地址

https://github.com/jiaxuansun/wordcount

PSP表格

PSPPSP阶段预估耗时(分钟)实际耗时(分钟)
Planning计划105
·Estimate估计这个任务需要多少时间105
Development开发510500
·Analysis需求分析 (包括学习新技术)4030
·Design Spec生成设计文档2020
·Design Review设计复审 (和同事审核设计文档)1010
·Coding Standard代码规范 (为目前的开发制定合适的规范)1010
·Design具体设计3030
·Coding具体编码300240
·Code Review代码复审4040
·Test测试(自我测试,修改代码,提交修改)60120
Reporting报告7080
·Test Report测试报告3040
·Size Measurement计算工作量1010
·Postmortem & Process Improvement Plan事后总结, 并提出过程改进计划3030
合计590585

解题思路

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

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

  • 查找文件功能:查找输入的文件需要支持如"*.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

转载于:https://www.cnblogs.com/ss07/p/8605629.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值