无所事事,忽然想到统计一下自己写的项目的代码行数。


#!/usr/bin/env python3

import os, sys, getopt

thisFile = os.path.splitext(os.path.basename(__file__))[0]
thisVersion = '1.0.0'

# 输出程序标题
def printTitle():
	title = 'Line Counter by Meniny'
	sep = ''
	for i in range(len(title) + 2):
		sep += '-'
	print(sep + '\n ' + title + '\n' + sep)

# 输出帮助信息
def help():
	print(thisFile + '(' + thisVersion + ')'+ ' Usage:')
	print('-h, --help:         show this help message')
	print('-v, --version:      show version info')
	print('--p, --path:        Setter path with argument')
	print('--d, --detail:      enable detail log')
	print('--e, --exception:   enable exception log')
	print('--r, --redirection: optimize log for redirection')

# 输出版本信息
def version():
	print(thisFile + ' Version: ' + thisVersion)

# 结束程序
def exit():
	sys.exit(1)

def main(argv):
	printTitle()
	extensions = ['.h', '.m', '.swift', '.js', '.mm', '.c', '.cpp', '.py', '.rb', '.hs', '.sh', '.java', '.pr']
	totalCount = 0
	fileCount = 0
	try:
		# 提取选项与参数
		opts, args = getopt.getopt(argv[1:], 'hvo:', ['path=', 'detail', 'exception', 'redirection'])
		# 初始化路径与输出设置
		folder = ''
		detailBool = False
		exceptionBool = False
		redirectionBool = False
		# 校验选项和参数
		shouldAnalyse = True
		for o, a in opts:
			if o in ('-h', '--help'):
				help()
				shouldAnalyse = False
			elif o in ('-v', '--version'):
				version()
				shouldAnalyse = False
			elif o in ('--p', '--path'):
				folder = a
			elif o in ('--d', '--detail'):
				detailBool = True
			elif o in ('--e', '--exception'):
				exceptionBool = True
			elif o in ('--r', '--redirection'):
				redirectionBool = True
		if not shouldAnalyse:
			exit()
		hasOpts = len(opts) > 0
		if not hasOpts and len(folder) <= 0:
			# 路径为空且没有选项,输入路径
			folder = input('Path of project: ') + ''
		# 如果输入的路径为.或./或空,则设置为当前路径
		if folder == '.' or folder == './' or len(folder) <= 0:
			folder = os.getcwd()
		if not os.path.exists(folder):
			# 非法路径,提示并退出
			print('Invalid path!\n')
			exit()
		print('Path: ' + folder)
		# 如果没有选项,则询问输出设置
		if not hasOpts:
			if not detailBool:
				detail = input('Enable detail log? (y/n): ')
				detailBool = detail == 'y' or detail == 'Y'
			if not exceptionBool:
				exception = input('Enable exception log? (y/n): ')
				exceptionBool = exception == 'y' or exception == 'Y'
			if not detailBool and not redirectionBool:
				redirection = input('Optimize log for redirection? (y/n): ')
				redirectionBool = redirection == 'y' or redirection == 'Y'
		# 显示输出设置的状态
		print('Log Status:')
		if detailBool:
			print('Detail log enabled')
		else:
			print('Detail log disabled')
		if exceptionBool:
			print('Exception log enabled')
		else:
			print('Exception log disabled')
		if redirectionBool:
			print('Log optimized for redirection')
		else:
			print('Log NOT optimized for redirection')
		print('Analyzing...')
		# 遍历目录
		for root, dirs, files in os.walk(folder):
			# 遍历文件
			for fileName in files:
				# 后缀名是需要统计的文件后缀
				if os.path.splitext(fileName)[1] in extensions:
					path = os.path.join(root, fileName)
					if os.path.exists(path):
						# 存在则打开
						handler = open(path, "rU", 1, "utf8")
						try:
							fileCount += 1
							thisCount = 0
							for line in handler:
								# 统计非空行
								if line.split():
									thisCount += 1
							totalCount += thisCount
							# 输出每个文件及行数
							if detailBool:
								print('%i - %s' %(thisCount, path))
							else:
								# 输出处理进度
								if redirectionBool:
									print('Handled file(s): %i, Non-blank line(s): %i' %(fileCount, totalCount), end='\r')
						except Exception as exp:
							# 输出解析错误的信息
							if not exceptionBool:
								print('\nERROR: %s\nFILE: %s\n' %(exp, path))
						finally:
							handler.close()
		# 全不解析完毕,输出统计结果
		print('You have %i non-blank line(s) of code in %i file(s).'%(totalCount, fileCount))
		print('The valid file extensions are %s' %extensions)
	except getopt.GetoptError as err:
		# 错误的选项,输出错误并退出
		print(str(err))
		help()
		exit()
  
if __name__ == '__main__':
	main(sys.argv)

保存后,你可以在终端中的任意工作目录下使用 python3 fileFullPath 来执行这个 Python 文件,程序会指引你输入工程路径等操作。

此外:

  • 你可以使用 -h 来查看帮助

  • 使用 -v 选项查看版本信息

  • 为了方便将结果重定向到指定文件,还提供了 --p projectPath--path projectPath 选项设定工程路径。

  • 使用 --d--detail 让程序输出每一个分析过的文件及其行数的详细信息。如果你没有启用这个特性,程序将会自动输出处理进度,你可以通过 --r--redirection 开屏蔽。

  • 如果解析文件发生错误,你还可以使用 --e--exception 来启用错误输出功能。