前言
本文基于上篇代码抽取功能优化(一)进行了一些优化,增加了对python多行注释、C++多行注释以及markdown的处理,修复了一些小bug,将抽取准确率提升至92%。
一、代码抽取构建思路
二、各模块介绍
1.提取markdown中的code
思路:
1、判断```是否在该行中,在的话count+1,并取出该行行号
2、得到行号后,从原list中取出行号之间的内容
整体还需看代码才能更好的理解
def extract_markdown(data_list):
"""提取markdown中的代码,即"```"中的内容
Args:
data_list: 文本列表
Returns:
codes: 提取出来的代码段(list)
texts: 提取出的文本(string类型)
"""
idxs = []
count = 0
for idx, line in enumerate(data_list):
if "```" in line:
idxs.append(idx)
count += 1
if count < 2:
return [], data_list
else:
try:
assert (len(idxs) % 2) == 0
codes = []
texts = []
for idx, val in enumerate(idxs):
if idx % 2 == 0:
if idx == 0:
text = data_list[:idxs[idx]]
else:
text = data_list[idxs[idx - 1] + 1: idxs[idx]]
code = data_list[idxs[idx] + 1: idxs[idx + 1]]
code = '\n'.join(code)
text = '\n'.join(text)
codes.append(code)
texts.append(text)
if idx == len(idxs) - 1:
text = data_list[idxs[idx] + 1:]
text = '\n'.join(text)
texts.append(text)
texts = ''.join(texts)
except:
return [], data_list
return codes, texts
2.提取python多行注释的索引
整体思路与提取markdown中的code类似,这里不再赘述,直接看代码:
def extract_py_annotation_idx(data_list, annotation= "'''"):
"""提取python多行注释内容
Args:
data_list: 文本列表
Returns:
idx: 返回的索引
"""
idxs = []
count = 0
for idx, line in enumerate(data_list):
if annotation in line:
idxs.append(idx)
count += 1
if (count % 2) == 1:
return []
else:
assert (len(idxs) % 2) == 0
return idxs
3.提取C++多行注释
这里与前面两个稍有不同,但整体思路也是一样
def extract_cpp_annotation_idx(data_list):
"""提取/* */中的多行注释行索引
Args:
data_list: 文本列表
Returns:
idx: 注释索引列表
"""
idxs = []
count = 0
for idx, line in enumerate(data_list):
if line.find('/*') != -1 and line.find('*/') != -1:
continue
elif line.find('/*') != -1:
count += 1
idxs.append(idx)
elif line.find('*/') != -1:
count += 1
idxs.append(idx)
if (count % 2) == 1:
return []
else:
return idxs
不管是哪种代码的多行注释,都需要注意一点:这些注释符一定是成对存在的!
4.代码判定逻辑
1、输入为line,对每一行代码进行判定,是代码返回True,否则返回False。
2、对传入的line,先直接判定为False,满足一定的条件后,再置为True。
def is_code_new(self, line, feature_list, annotation_list, text_keywords_list, code_print_list):
code_flag = False #先置为False,满足一定条件后再判定为True
# count = 0
# cn_num = getnum_of_cn(line)
# en_num = getnum_of_en(line)
cn_and_symbol_num = getnum_of_cn_and_symbol(line) # 计算中文字符及中文标点符号的个数
for symbol in feature_list: # 遍历代码关键字
if is_sub_string(line, symbol): # 判断该行是否包含代码关键字
code_flag = True #包含的话,置为True
for annotation in annotation_list: #遍历各种代码的注释符
if is_sub_string(line, annotation): #判定是否包含注释符
code_flag = True #包含注释符,置为True,跳出注释遍历
break
else: #不包含注释符
for text_keyword in text_keywords_list: #遍历文本关键词,如果包含文本关键词,置为False
if is_sub_string(line, text_keyword):
code_flag = False
break
if cn_and_symbol_num > 30:
# 如果不包含注释,且中文字符数大于30,则置为False
# 考虑到大于30个中文字符,也有可能是print的情况,因此该段代码必须放在判断print条件之前
code_flag = False
# 如果不包含注释,且中文字符数大于0,便考虑是否是print输出的情况
# 如果确实是print的输出,则置为True
if cn_and_symbol_num > 0:
for print_keyword in code_print_list:
if is_sub_string(line, print_keyword):
code_flag = True
break
else:
#如果不是print的情况,则考虑到是否是定义的字典
# 如python定义字典,里面存在这种情况:
# dict = {
# 'name' : '张三',
# '性别': '男'
# }
#如果是上述类似情况,则置为True
if re.search(r'[\=\:]\s*?[\'\"].*?[\'\"]', line):
code_flag = True
else:
code_flag = False
# 考虑到有些报错也会被误判为代码,这里排除类似以下情况的报错
# Trace back in line xxx
# 其中xxx可以是任意数字
# 只要该行包含line xxx,则置为False
if is_line_num(line):
code_flag = False
return code_flag
5.后续的优化
1、虽然准确率已经有90+%,但测试数据仅有400条,可能漏掉了一些情况,比如SQL代码,51汇编代码,以及一些其他的关键字段,后续会围绕这几个点去优化,争取将效果提升至95+%。
2、考虑过将所有语言的保留字加入code_feature_list中,但这样的话,准确率虽然有所提升,但代码执行效率将下降很多,由于代码提取服务作为一个基础模块,必须要兼顾效率及准确率,因此,两者需有个平衡。
总结
1、经过20多天的努力,终于将代码提取服务的效果提升至90+%,也算是个不错的开始。
2、一个人或许可以走得很快,但一群人却能够走的更远
3、感恩遇见这么好的一个团队🌹🌹🌹
4、加油