您的位置:首页 > 编程语言 > Python开发

[置顶] 利用python实现批量插入打印信息的方法

2016-03-12 20:22 966 查看
使用打印信息是调试程序的必备手段,但是面对下面两种情况:

1.如果程序代码/源文件较多,而一时之间又无法确定问题范围,这个时候可能需要在多个文件插入打印信息

2.刚刚接手维护大型模块,想要了解运行流程,需要在有可能运行到的地方都加入trace

上述情况,如果手动在每个函数的开头,每个判断语句都加入trace,会耗费很多时间

python是处理数据的一个好工具,结合正则表达式,我们可以写一个脚本,实现:

在每个函数/每个判断的入口打印函数名/判断的内容,当然前提是必须是在{}内

同时,我们要避免在循环语句内打印

下面是脚本:

import re
import os
import os.path

rootpath = ''#代码所在的路径
filterList = [];#要过滤的文件
needFilter = False

for parent, dirs, files in os.walk(rootpath):
for f in files:
for idx in range(len(filterList)):
if f == filterList[idx]:
needFilter = True
break
if needFilter == True:
needFilter = False
continue
fname = os.path.splitext(f)#将文件名和后缀名分离
if fname[1] == '.c' or fname[1] == '.cpp':
fd = open(os.path.join(parent,f))
code = fd.read()
fd.close()
newStr1 = re.sub(r'(\S+)(.*)(\()(.*)(\))(\s*)([^\{|\}|\(|\)]*)(\s*)(\{)(?!\})(\s*)',r'\1\2\3\4\5\6\7\8\9\10printf("%s,%d,\1\2\3\4\5\\n",__FILE__,__LINE__);\10',code)
newStr2 = re.sub(r'(//)(.*)(\{)(\s*)printf\("%s,%d,\S+.*\(.*\)\\n",__FILE__,__LINE__\);',r'\1\2\3\4\1printf("%s,%d,\S+.*\(.*\)\\n",__FILE__,__LINE__);',newStr1)
newStr3 = re.sub(r'(=+)(\s*)(\{)(\s*)printf\("%s,%d,\S+.*\(.*\)\\n",__FILE__,__LINE__\);',r'\1\2\3\4',newStr2)
newStr4 = re.sub(r'(.*(for|while)\s*\([^\{]*\{)\s*printf\("%s,%d,\S+.*\(.*\)\\n",__FILE__,__LINE__\);',r'\1',newStr3)
newStr5 = re.sub(r'(.*(enum|extern)(.*|\s*)\{)\s*printf\("%s,%d,\S+.*\(.*\)\\n",__FILE__,__LINE__\);',r'\1',newStr4)
newStr6 = re.sub(r'struct(\s*)(.*)(\s*)(\{)(\s*)printf\("%s,%d,\S+.*\(.*\)\\n",__FILE__,__LINE__\);(\s*)',r'struct\1\2\3\4\5',newStr5)
newStr7 = re.sub(r'(\(\")(.*[^\\])\"(.*[^\\])\"(.*\",)',r'\1\2\\"\3\\"\4',newStr6)
newStr8 = newStr7
while True:
newStr7 = re.sub(r'(\(\")(.*[^\\])\"(.*[^\\])\"(.*\",)',r'\1\2\\"\3\\"\4',newStr7)
if newStr8 == newStr7:
break
newStr8 = newStr7
fd=file(os.path.join(parent,f),"w+")
fd.write(newStr8)
fd.close()


运行这个脚本后,会遍历rootpath下的所有文件(包括子目录下的文件),然后过滤掉我们指定的文件,要过滤的文件放在 filterList 里,过滤掉后,在剩下的文件里,筛选出C/C++源文件,对每个筛选出来的文件,进行以下操作:

1.从文件读取出代码

2.利用正则表达式添加trace

3.将代码写回文件

python对文件的遍历十分方便,这里最主要的就是对正则表达式的使用,下面解释每条正则表达式的作用:

1.

查找:(\S+)(.)(()(.)())(\s*)([^{|}|(|)])(\s)({)(?!})(\s*)

替换为:\1\2\3\4\5\6\7\8\9\10printf(“%s,%d,\1\2\3\4\5\n”,FILE,LINE);\10

效果:

下面的代码

{



}

会被替换成

{

printf(“%s,%d\n”,FILE,LINE);



}

2.

查找:(//)(.)({)(\s)printf(“%s,%d,\S+.(.)\n”,FILE,LINE);

替换为:\1\2\3\4\1printf(“%s,%d,\S+.(.)\n”,FILE,LINE);

效果:

下面的代码

//…{

printf(“%s,%d\n”,FILE,LINE);

会被替换成

//…{

// printf(“%s,%d\n”,FILE,LINE);

这是为了在被消除的代码后面加上的打印,否则会有编译错误

3.

查找:(=+)(\s*)({)(\s*)printf(“%s,%d,\S+.(.)\n”,FILE,LINE);

替换为:\1\2\3\4

效果:

={printf(“%s,%d\n”,FILE,LINE);

会被替换成

={

当=后跟随着{表明是赋值操作,打印需要去掉

4.

查找:(.(for|while)\s([^{]{)\s*printf(“%s,%d,\S+.(.*)\n”,FILE,LINE);

替换为:\1

效果:

把while和for循环里的打印语句去掉

5.

查找:(.(enum|extern)(.|\s*){)\s*printf(“%s,%d,\S+.(.)\n”,FILE,LINE);

替换为:\1

效果:

去掉枚举和extern里的打印语句

6.

查找:struct(\s*)(.)(\s)({)(\s*)printf(“%s,%d,\S+.(.)\n”,FILE,LINE);(\s*)

替换为:struct\1\2\3\4\5

效果:

去掉结构体定义里的打印语句

7.

查找:((\”)(.[^\])\”(.[^\])\”(.*\”,)

替换为:\1\2\”\3\”\4

效果:

因为插入的打印语句会把{前的一行内容打印出来,考虑下面的情况

if(a == “test”)

插入打印语句后

if(a == “test”){

printf(“%s,%d,a == “test”\n”,FILE,LINE);

由于”“没有被转义,所以编译会出错,上面的正则替换就是为了增加转义,增加后:

if(a == “test”){

printf(“%s,%d,a == \”test\”\n”,FILE,LINE);

使用循环是为了应对修改的数据里有多组”“,当处理结果和上次得到的结果一样时,说明每对”“都已经被处理完,加上了转移字符

如果发现自己的代码还有特殊的情况要处理,可以利用正则表达式继续处理,一般C/C++的情况上面应该可以覆盖
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: