2021秋软工实践第一次个人编程作业

Sevennn 2021-09-18 21:09:59

2021秋软工实践第一次个人编程作业

这个作业属于那个课程构建之法-2021年秋-福州大学软件工程
这个作业要求在哪里2021年秋软工实践第一次个人编程作业
这个作业的目标编码完成C/C++文件的关键字提取、性能分析与代码优化、GitHub初使用
学号031904140

 


PSPPersonal Software Process Stages预估耗时(分钟)实际耗时(分钟)
Planning计划3060
Estimate估计这个任务需要多少时间1010
Development开发--
Analysis需求分析 (包括学习新技术)3060
Design Spec生成设计文档--
 Design Review设计复审 (审核设计文档)--
Coding Standard代码规范 (为目前的开发制定合适的规范)3050
Design具体设计100150
Coding具体编码500600
Code Review代码复审100100
Test测试(自我测试,修改代码,提交修改)60100
Reporting报告--
Test Report测试报告--
Size Measurement计算工作量5030
Postmortem & Process Improvement Plan事后总结, 并提出过程改进计划10090
 合计10101150

目录

要做什么?

开始编码

读入文件

关键字提取

switch-case结构匹配

if-else 或 if-elseif-else结构匹配

样例代码测试结果

单元测试与性能分析

单元测试

性能分析

总结

要做什么?

  1. 有四项要求,完成每项要求前要完成前置的各项要求;
  2. 基本要求是统计文件的关键词数目,注释和字符串中出现的“关键词”是假的关键词;
  3. if-else或if-else if-else 必须以else结尾才算作一组,降低了难度!
  4. 需统计的关键词为:
    kw_list = ['auto','break','case','char','const','continue','default','do',
               'double','else','enum','extern','float','for','goto','if',
               'int','long','register','return','short','signed','sizeof',
               'static','struct','switch','typedef','union','unsigned',
               'void','volatile','while']

开始编码

  • 读入文件

  • 输入参数为代码文件的路径,首先判断所给文件是否为.c/.cpp
  • 通过逐行读取,将文件内容存于text中
ls = []
   
if file_name.endswith('.cpp') or file_name.endswith('.c'):
    fr = open(file_name, 'r', encoding='UTF-8')
    for line in fr:
        ls.append(line)
    fr.close()
text = "".join(ls)
  • 关键字提取

  • 利用Python字符串的count()方法,输出关键词的个数
Count = {}
for word in kw_list:
    num = text.count(word)
    if num != 0:
        Count[word] = num

items = list(Count.items())
count_sum = 0
for i in range(len(items)):
    kw , count = items[i]
    print(kw,'num : ',count)
    count_sum += count
print('total num :',count_sum)
  • 输入样例代码统计total num:36?(实际为35)仔细寻找发现原来是double被识别为do,计入了do num;
  • 同时,上述代码无法识别注释及字符串中出现的假性关键词
  • 于是放弃了字符串匹配,改用正则表达式匹配出完整的英文单词,同时匹配不需要的注释及字符串,删除二者一了百了!
  • 可参照正则表达式语法

正则表达式的用法在数据采集与融合技术课程中有过初步实践,这里给出匹配注释、字符串以及英文单词的表达式

注释// /* */ :\/\*([^\*^\/]*|[\*^\/*]*|[^\**\/]*)*\*\/|\/\/.*

单引号 '':'.*'

双引号 "":\"([^\"]*)\"

英文单词:\b[a-zA-Z]+\b

 另外可通过Regex在线测试正则表达式

import re
reg = r"(\/\*([^\*^\/]*|[\*^\/*]*|[^\**\/]*)*\*\/|\/\/.*|'.*'|\"([^\"]*)\")"
def replace_comment(file_name):
    '''
    替换注释
    :param file_name: 文件路径
    :return: 替换注释(字符串)后的str
    '''
    ls = []
    if file_name.endswith('.cpp') or file_name.endswith('.c'):
        fr = open(file_name, 'r', encoding='UTF-8')
        for line in fr:
            ls.append(line)
        fr.close()
    text = "".join(ls)

    comment = re.finditer(reg,text)
    for match in comment:
        text = text.replace(match.group(),' ')
    return text
reg = r'\b[a-zA-Z]+\b'
text = replace_comment(path)
line = re.findall(reg, text)

def kw_num():
    Count = {}
    for word in kw_list:
        num = line.count(word)
        if num != 0:
            Count[word] = num

    items = list(Count.items())
    count_sum = 0
    for i in range(len(items)):
        kw, count = items[i]
        print(kw, 'num : ', count)
        count_sum += count
    print('total num :', count_sum)
  • switch-case结构匹配

  • 如何判断case属于哪一个switch呢?
  • 第一个想法是利用default,遇到default便结束此次匹配。可转念一想,并不是每个switch都有default;
  • case总是伴随着switch的出现而出现,那为何不用下一个switch的出现标记上一轮匹配的结束呢?(忽然想到了有嵌套的可能性)
reg = r'\b[a-zA-Z]+\b' 
text = replace_comment(path)
line = re.findall(reg, text)

def switch_num():
    switch_num = 0
    switch_flag = 0  
    case_num = []
    if line.count('switch') == 0:
        print('No switch')
        return 0
    for kw in line:
        if kw == 'switch':
            switch_num += 1
            switch_flag = 1
            case_num.append(0)
        if switch_flag == 1 and kw == 'case':
            case_num[switch_num-1] += 1
    for i in range(len(case_num)):
        print('Case num for No.{} switch: {}'.format(i+1, case_num[i]))
  • if-else 或 if-elseif-else结构匹配

  • 这个要求与大二算法课上括号的匹配很是相似,于是想到了用栈来解决这个问题:遇到if便压入栈,遇到else就弹出栈顶元素。

class Stack(object):
    def __init__(self):
        self.items = []
    def isEmpty(self):
        return self.items == []
    def push(self, item):
        self.items.append(item)
    def pop(self):
        return self.items.pop()
    def peek(self):
        return self.items[len(self.items)-1]
    def size(self):
        return len(self.items)
    def value(self,num):
        return self.items[num]
  • 如何保证else if中的if不被当作一个新的if而压入栈呢?......
  • 于是我继续沿袭了之前的做法,删了它一了百了!这次删的是else if之间的空格。

正则表达式匹配else if :\be.*?f\b 

  • 接下来的做法是:遇到 if 及 elseif 便将其压入栈,遇else时弹出栈顶的元素。要注意两个连续的 elseif 只压入一个即可。
def if_else_elseif_num():
    text_elseif = replace_space(text)
    line_elseif = re.findall(reg, text_elseif)
    ifelse_num = 0
    ifelifelse_num = 0
    ifelifelse_flag = 0
    stack = Stack()
    for kw in line_elseif:
        if kw == 'if':
            stack.push('if')
        elif kw == 'elseif' and stack.value(-1) == 'if':
            stack.push('elseif')
        elif kw == 'else':
            while (stack.value(-1) != 'if'):
                ifelifelse_flag = 1
                stack.pop()
            stack.pop()
            if ifelifelse_flag:
                ifelifelse_num += 1
                ifelifelse_flag = 0
            else:
                ifelse_num += 1

    print('if-else num: {}'.format(ifelse_num))
    print('if-elif-else num: {}'.format(ifelifelse_num))
  • 样例代码测试结果

单元测试与性能分析

  • 单元测试

  • 使用coverage统计单元测试覆盖率,需安装coverage
pip install coverage
  • 命令行输入
coverage run <待测代码路径>
  • 可通过以下代命令生成html文件,在浏览器中查看,如下图所示:
coverage html

  • 性能分析

  • 用 line_profiler 进行逐行分析(可使用pip/conda安装),用修饰器(@profile)标记选中的函数。
  • 这里的测试样例为原样例代码×10
kernprof -l -v

    • 附:commit截图

      仓库截图

      总结

    1. 通过历时三天的编程和测试,浏览了上百个网页,真切体会到编码只是任务的一小部分,更多的时间是用在分析需求、查找资料、优化代码;
    2. 将自己所学的知识融会贯通是一个很奇妙的过程,通过这次任务,对正则表达式有了更多的了解。在熟知各字符的语义的基础上,可以尝试自己编写正则表达式,对之后的爬虫实践也会有较大的帮助;
    3. 同时也学会了运用各种工具对代码进行分析,逐步优化。
    ...全文
    691 2 打赏 收藏 转发到动态 举报
    AI 作业
    写回复
    用AI写文章
    2 条回复
    切换为时间正序
    请发表友善的回复…
    发表回复
    云舒先生º 2021-09-19
    • 打赏
    • 举报
    回复

    coverage测试代码的时候对代码的格式有要求吗

    Sevennn 2021-09-19
    • 举报
    回复
    @云舒先生º 没有喔

    189

    社区成员

    发帖
    与我相关
    我的任务
    社区描述
    福州大学软件工程教学,推行邹欣老师“构建之法”。
    软件工程 高校
    社区管理员
    • Dawnfox
    • REP1USONE
    • 纪华裕
    加入社区
    • 近7日
    • 近30日
    • 至今
    社区公告
    暂无公告

    试试用AI创作助手写篇文章吧