[python]寫一個統計代碼行數的codeCounter

 某一天過去SY那兒,突發奇想說要寫一個統計代碼行數的小程序。說幹就幹,約定了一個時間——週六,來把這個想法給實現了。當然這個項目人家做過的也未必,google一下,果然有非常優秀的win下面的代碼統計工具sourceCounter。當然我們是用python來寫,確定了數據結構和算法之後,我們就開始實現了。


我們要實現的是一個能夠遍歷指定的文件夾或文件,數出有多少行,然後好好將這個信息放到樹的節點裏面。總之,這是一個N叉樹,N取決於該目錄下面,有多少個子目錄或子文件。我們使用列表list來模擬樹型結構:

parentDir

    subDir

在數據結構裏面就是 [{counter: co, name: parentDir}, [{couter:co2, name:subDir}[]]]。當然這是最簡單的情況,複雜一點就是,很多層嵌套,視目錄深度而決定。總之就是發現了一個文件或者目錄,就遞歸地擴展下去。上代碼:

 

def walk_dir(self,folder_tree, topdown=True): 		for root, dirs, files in os.walk(folder_tree[0]['name'], topdown): 			for name in files: 				if name[0] == '.': 					continue 				 				if self.my_pattern.match(name): 				 					path_name = os.path.join(root,name) 					if os.path.islink(path_name): 						continue 					# calculate the summry of the file 					count_result = self.count_code_of_file(path_name) 					# insert into the tree 					 					sub_folder_tree = [{'name':path_name,'counter': count_result},[]] 					folder_tree[1].append(sub_folder_tree) 					# sum 					folder_tree[0]['counter'] = folder_tree[0]['counter'] + count_result 				 			for name in dirs: 				if name[0] == '.': 					continue 				path_name = os.path.join(root,name) 				# print(path_name) 				sub_folder_tree = [{'name':path_name,'counter': 0},[]] 				folder_tree[1].append(sub_folder_tree) 				self.walk_dir(sub_folder_tree, topdown) 				# sum 				folder_tree[0]['counter'] = folder_tree[0]['counter'] + sub_folder_tree[0]['counter'] 			return

這就是整個算法的核心部分,用os.walk整個dir,得到一棵樹。一開始我們提出了兩種方案:一,先生成樹,再統計代碼,因爲需要回填;二,在生成樹的同時,計算出代碼行數。SY很敏捷,一下自己想出直接在後面加上folder_tree[0]['counter'] = folder_tree[0]['counter'] + sub_folder_tree[0]['counter']. 也就是每次遍歷完一棵子樹,就更新父節點的counter數據。這其中使用了遞歸的原理。code complete裏面說,遞歸不是用來求求階乘和斐波那契數列的,而是需要使用在更有效的需要棧的地方,我想說,這裏就是。其核心原理就是每一層,構造一個[{counter:co, name:na }[]], 插入到父節點的[]中,構造樹的過程,也完成了有關的計算。

接下來就是實現驅動腳手架了(一些數據輸入和函數調用),然後實現打印模塊,打印模塊,需要表現縮進,故而有一個參數是tabs次數。具體實現如下:

 

def print_tree(self,folder_tree, tabs = 0,topdown=True): 		if os.path.isdir(folder_tree[0]['name']): 			print ' ' 			print '   '*tabs,'+',folder_tree[0]['name'] , ' : ' ,folder_tree[0]['counter'] 			 		else: 			file_name = os.path.split(folder_tree[0]['name']) 			print '   '*tabs,'+',file_name[1], ' : ' ,folder_tree[0]['counter'] 			return 		if folder_tree[1]: 			 			for sub_tree in folder_tree[1]: 				self.print_tree(sub_tree,tabs +1) 		else: 			return

一切就是這麼簡單,然後就定義一下有哪些文件類型了,這個可以用正則表達式來完成:

 

my_pattern = re.compile(r'[a-zA-Z1-9]+.(py|c|java|php|cpp|css|html|xml|htm|js|cs|h|asm|sh|ruby|perl)$')

很顯然是普通文件名,如果要加入下劃線則在把字符串改成‘[a-zA-Z1-9]+[a-zA-Z1-9_.]* .(py|c|java省略’。

最後,如果想要把樹打印到文件裏面也是可以的,之需要在print前面加上>>log_file變成 print >>log_file。總體代碼不超過100行。當然使用linux下面的shell一句就能搞定:

 

find /a -name "*.c" |xargs cat|grep -v ^$|wc -l

當然這其實是linux應用程序的組合使用,grep等等強大的工具,表示還沒有到那個神級別。好吧,窗外的雨下個不停,可是我的手指敲擊鍵盤的聲音,卻要漸漸停息了。

git代碼: https://github.com/bibodeng/pyCodeCounter/blob/master/codeCounter.py

by bibodeng 2013-3-31

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章