Python实现删除目录里所有C源码的注释
0前言
我老板之前演讲说了一个删除C工程里所有注释的方法,在实际工作中十分有用,他使用perl写的,很简洁,但是我不会,鉴于我会的脚本语言只有Python,所以打算自己写一个更加完善的
1完整复制整个工程
为了给自己留一个带注释的工程,同时也害怕程序突然出错,所以还是先完整复制整个工程目录,在新的目录里做文本处理。通过递归一级一级的复制文件,需要 import shutil
# 完整复制整个目录
def copy_dir(src_path, target_path):
if not os.path.isdir(target_path):
os.mkdir(target_path)
filelist_src = os.listdir(src_path)#用于返回一个文件名和目录名
for file in filelist_src:#遍历所有的文件或文件夹
src_path_read_new =os.path.join(os.path.abspath(src_path),file)
target_path_write_new = os.path.join(os.path.abspath(target_path),file)
if os.path.isdir(src_path_read_new):#判断该读入路径是否是目录文件夹,如果是文件夹执行递归
if not os.path.exists(target_path_write_new):#判断目标路径是否存在该文件夹
os.mkdir(target_path_write_new)#没有就创建文件夹
copy_dir(src_path_read_new,target_path_write_new)#递归
else:#如果是文件,执行复制
shutil.copy(src_path_read_new,target_path_write_new)
2使用正则表达式寻找目录里.c.h文件
传入目录名,返回该目录下的所有.c.h文件的绝对路径
# 找到一个目录里的所有.c .h文件
def find_dir(dir_name):
file_list = []
for path_name, dir, files_name in os.walk(dir_name):
for file in files_name:
if bool(re.search(".h|.c$", file)) != 0:
file_list.append(os.path.join(path_name, file))
return file_list
3 找到注释并用空字符替换
def treat_comment(file):
bds0 = r'\/\/.*' # 标准匹配单行注释
bds1 = r'\/\*(?:[^\*]|\*+[^\/\*])*\*+\/' # 标准匹配多行注释 可匹配跨行注释
target0 = re.compile(bds0) # 单行注释
target = re.compile(bds1) # 编译正则表达式
# 注意编码,可加encoding,默认是gbk
with open(file, 'r') as f:
data = f.read()
# 找出两种注释
comment1 = target0.findall(data)
comment2 = target.findall(data)
# 此时已经找到了注释所在,接下来就是删除注释
comment = comment1 + comment2
for i in comment:
#这里非常关键,普通的替换,会将data里所有数据的i都找出来替换
# 第三个参数1控制其找到第一个匹配就替换,然后就结束了
data = data.replace(i, '', 1) # 替换为空字符串
f = open(file, 'w')
f.write(data)
f.close()
data = data.replace(i, '', 1) # 替换为空字符串
这里非常关键,普通的替换,会将data里所有数据的i都找出来替换掉,而第三个参数1控制其找到第一个匹配就替换,然后就结束了,这样就很好解决了一个问题:比如有这样一段注释
//
//printf("hello");
正则匹配到了'//' 和 '//printf("hello");'
, 那么不加参数1处理完一个循环之后变成
printf("hello");
再处理第二个循环时就会找'//printf("hello");'
做替换, 结果就是data里已经没有了这个字符串,不会做任何处理,最终的结果就是留下了printf("hello");
4删除空白行
这里使用了正则和列表推导式
# 删除文件的行,这个行以空格开头(空格可能没有可能连续很多个)紧接着是\n
def remove_line(file):
lines = [l for l in open(file, "r") if bool(re.search("^\s*\n", l)) == 0]
# print(lines)
fd = open(file, "w")
fd.writelines(lines)
fd.close()
5汇总使用
获取时间戳作为新目录名,sys.argv
获取命令行执行时的参数列表
$ python test.py arg1 arg2 arg3
参数个数为: 4 个参数。
参数列表: ['test.py', 'arg1', 'arg2', 'arg3']
if __name__ == '__main__':
# 旧的目录
now_time = datetime.datetime.now().strftime("%Y-%m-%d %H-%M-%S")
# old_dir = '.\\C_Project_demo'
if len(sys.argv) == 1:
old_dir = os.path.dirname(__file__)
else:
old_dir = sys.argv[1]
new_dir = old_dir + '_new_' + now_time
copy_dir(old_dir, new_dir)
files = find_dir(new_dir)
print(files)
for file in files:
treat_comment(file)
# 删除新文件的空白行
remove_line(file)
使用方法
上面所有方法放在一个文件里,假设取名为remove_comment.py
- 将
remove_comment.py
放在想要处理的工程里,双击即可在同级目录找到处理完成的目录 - 在命令行输入
python 你的py文件路径 想要处理的工程目录