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

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


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

parentDirhtml

    subDir
java

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

 

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 }[]], 插入到父節點的[]中,構造樹的過程,也完成了有關的計算。linux

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

 

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

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

 

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

相關文章
相關標籤/搜索