使用Python设计一个代码统计工具


Posted in Python onApril 04, 2018

问题

设计一个程序,用于统计一个项目中的代码行数,包括文件个数,代码行数,注释行数,空行行数。尽量设计灵活一点可以通过输入不同参数来统计不同语言的项目,例如:

# type用于指定文件类型
python counter.py --type python

输出:

files:10
code_lines:200
comments:100
blanks:20

分析

这是一个看起来很简单,但做起来有点复杂的设计题,我们可以把问题化小,只要能正确统计一个文件的代码行数,那么统计一个目录也不成问题,其中最复杂的就是关于多行注释,以 Python 为例,注释代码行有如下几种情况:

1、井号开头的单行注释

# 单行注释

2、多行注释符在同一行的情况

"""这是多行注释"""
'''这也是多行注释'''
3、多行注释符

"""
这3行都是注释符
"""

我们的思路采取逐行解析的方式,多行注释需要一个额外的标识符in_multi_comment 来标识当前行是不是处于多行注释符当中,默认为 False,多行注释开始时,置为 True,遇到下一个多行注释符时置为 False。从多行注释开始符号直到下一个结束符号之间的代码都应该属于注释行。

知识点

如何正确读取文件,读出的文件当字符串处理时,字符串的常用方法

简化版

我们逐步进行迭代,先实现一个简化版程序,只统计Python代码的单文件,而且不考虑多行注释的情况,这是任何入门 Python 的人都能实现的功能。关键地方是把每一行读出来之后,先用 strip() 方法把字符串两边的空格、回车去掉

# -*- coding: utf-8 -*-
"""
只能统计单行注释的py文件
"""
def parse(path):
 comments = 0
 blanks = 0
 codes = 0
 with open(path, encoding='utf-8') as f:
 for line in f.readlines():
  line = line.strip()
  if line == "":
  blanks += 1
  elif line.startswith("#"):
  comments += 1
  else:
  codes += 1
 return {"comments": comments, "blanks": blanks, "codes": codes}
if __name__ == '__main__':
 print(parse("xxx.py"))

多行注释版

如果只能统计单行注释的代码,意义并不大,要解决多行注释的统计才能算是一个真正的代码统计器

# -*- coding: utf-8 -*-
"""

可以统计包含有多行注释的py文件

"""
def parse(path):
 in_multi_comment = False # 多行注释符标识符号
 comments = 0
 blanks = 0
 codes = 0
 with open(path, encoding="utf-8") as f:
 for line in f.readlines():
  line = line.strip()
  # 多行注释中的空行当做注释处理
  if line == "" and not in_multi_comment:
  blanks += 1
  # 注释有4种
  # 1. # 井号开头的单行注释
  # 2. 多行注释符在同一行的情况
  # 3. 多行注释符之间的行
  elif line.startswith("#") or \
    (line.startswith('"""') and line.endswith('"""') and len(line)) > 3 or \
   (line.startswith("'''") and line.endswith("'''") and len(line) > 3) or \
   (in_multi_comment and not (line.startswith('"""') or line.startswith("'''"))):
  comments += 1
  # 4. 多行注释符的开始行和结束行
  elif line.startswith('"""') or line.startswith("'''"):
  in_multi_comment = not in_multi_comment
  comments += 1
  else:
  codes += 1
 return {"comments": comments, "blanks": blanks, "codes": codes}
if __name__ == '__main__':
 print(parse("xxx.py"))

上面的第4种情况,遇到多行注释符号时,in_multi_comment 标识符进行取反操作是关键操作,而不是单纯地置为 False 或 True,第一次遇到 """ 时为True,第二次遇到 """ 就是多行注释的结束符,取反为False,以此类推,第三次又是开始,取反又是True。

那么判断其它语言是不是要重新写一个解析函数呢?如果你仔细观察的话,多行注释的4种情况可以抽象出4个判断条件,因为大部分语言都有单行注释,多行注释,只是他们的符号不一样而已。

CONF = {"py": {"start_comment": ['"""', "'''"], "end_comment": ['"""', "'''"], "single": "#"},
 "java": {"start_comment": ["/*"], "end_comment": ["*/"], "single": "//"}}
start_comment = CONF.get(exstansion).get("start_comment")
end_comment = CONF.get(exstansion).get("end_comment")
cond2 = False
cond3 = False
cond4 = False
for index, item in enumerate(start_comment):
 cond2 = line.startswith(item) and line.endswith(end_comment[index]) and len(line) > len(item)
 if cond2:
 break
for item in end_comment:
 if line.startswith(item):
 cond3 = True
 break
for item in start_comment+end_comment:
 if line.startswith(item):
 cond4 = True
 break
if line == "" and not in_multi_comment:
 blanks += 1
# 注释有4种
# 1. # 井号开头的单行注释
# 2. 多行注释符在同一行的情况
# 3. 多行注释符之间的行
elif line.startswith(CONF.get(exstansion).get("single")) or cond2 or \
 (in_multi_comment and not cond3):
 comments += 1
# 4. 多行注释符分布在多行时,开始行和结束行
elif cond4:
 in_multi_comment = not in_multi_comment
 comments += 1
else:
 codes += 1

只需要一个配置常量把所有语言的单行、多行注释的符号标记出来,对应出 cond1到cond4几种情况就ok。剩下的任务就是解析多个文件,可以用 os.walk 方法。

def counter(path):
 """
 可以统计目录或者某个文件
 :param path:
 :return:
 """
 if os.path.isdir(path):
 comments, blanks, codes = 0, 0, 0
 list_dirs = os.walk(path)
 for root, dirs, files in list_dirs:
  for f in files:
  file_path = os.path.join(root, f)
  stats = parse(file_path)
  comments += stats.get("comments")
  blanks += stats.get("blanks")
  codes += stats.get("codes")
 return {"comments": comments, "blanks": blanks, "codes": codes}
 else:
 return parse(path)

当然,想要把这个程序做完善,还有很多工作要多,包括命令行解析,根据指定参数只解析某一种语言。

补充:

Python实现代码行数统计工具

我们经常想要统计项目的代码行数,但是如果想统计功能比较完善可能就不是那么简单了, 今天我们来看一下如何用python来实现一个代码行统计工具。

思路:

首先获取所有文件,然后统计每个文件中代码的行数,最后将行数相加.

实现的功能:

统计每个文件的行数;
统计总行数;
统计运行时间;
支持指定统计文件类型,排除不想统计的文件类型;
递归统计文件夹下包括子文件件下的文件的行数;

排除空行;

# coding=utf-8
import os
import time
basedir = '/root/script'
filelists = []
# 指定想要统计的文件类型
whitelist = ['php', 'py']
#遍历文件, 递归遍历文件夹中的所有
def getFile(basedir):
 global filelists
 for parent,dirnames,filenames in os.walk(basedir):
  #for dirname in dirnames:
  # getFile(os.path.join(parent,dirname)) #递归
  for filename in filenames:
   ext = filename.split('.')[-1]
   #只统计指定的文件类型,略过一些log和cache文件
   if ext in whitelist:
    filelists.append(os.path.join(parent,filename))
#统计一个文件的行数
def countLine(fname):
 count = 0
 for file_line in open(fname).xreadlines():
  if file_line != '' and file_line != '\n': #过滤掉空行
   count += 1
 print fname + '----' , count
 return count
if __name__ == '__main__' :
 startTime = time.clock()
 getFile(basedir)
 totalline = 0
 for filelist in filelists:
  totalline = totalline + countLine(filelist)
 print 'total lines:',totalline
 print 'Done! Cost Time: %0.2f second' % (time.clock() - startTime)

结果:

[root@pythontab script]# python countCodeLine.py
/root/script/test/gametest.php---- 16
/root/script/smtp.php---- 284
/root/script/gametest.php---- 16
/root/script/countCodeLine.py---- 33
/root/script/sendmail.php---- 17
/root/script/test/gametest.php---- 16
total lines: 382
Done! Cost Time: 0.00 second
[root@pythontab script]#

只会统计php和python文件,非常方便。

总结

以上所述是小编给大家介绍的使用Python设计一个代码统计工具,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

Python 相关文章推荐
深入浅析Python中的迭代器
Jun 04 Python
简单了解Django ContentType内置组件
Jul 23 Python
如何基于python实现脚本加密
Dec 28 Python
python3 Scrapy爬虫框架ip代理配置的方法
Jan 17 Python
python实现飞行棋游戏
Feb 05 Python
Python生成器实现简单"生产者消费者"模型代码实例
Mar 27 Python
PyQt5实现登录页面
May 30 Python
Python Socket TCP双端聊天功能实现过程详解
Jun 15 Python
python如何处理程序无法打开
Jun 16 Python
Python xlrd/xlwt 创建excel文件及常用操作
Sep 24 Python
python中time包实例详解
Feb 02 Python
Pyside2中嵌入Matplotlib的绘图的实现
Feb 22 Python
用 Python 连接 MySQL 的几种方式详解
Apr 04 #Python
Python基于辗转相除法求解最大公约数的方法示例
Apr 04 #Python
对numpy中数组元素的统一赋值实例
Apr 04 #Python
Python 元类实例解析
Apr 04 #Python
对numpy 数组和矩阵的乘法的进一步理解
Apr 04 #Python
Numpy数组的保存与读取方法
Apr 04 #Python
基于Python Numpy的数组array和矩阵matrix详解
Apr 04 #Python
You might like
探讨如何把session存入数据库
2013/06/07 PHP
jquery HotKeys轻松搞定键盘事件代码
2008/08/30 Javascript
jquery $.fn $.fx是什么意思有什么用
2013/11/04 Javascript
js阻止默认事件与js阻止事件冒泡示例分享 js阻止冒泡事件
2014/01/27 Javascript
javascript面向对象之对象的深入理解
2015/01/13 Javascript
javascript日期操作详解(脚本之家整理)
2015/09/05 Javascript
jquery实现点击弹出可放大居中及关闭的对话框(附demo源码下载)
2016/05/10 Javascript
Angularjs过滤器使用详解
2016/05/25 Javascript
原生JS实现轮播效果+学前端的感受(防止走火入魔)
2016/08/21 Javascript
基于jQuery实现火焰灯效果导航菜单
2017/01/04 Javascript
Bootstrap面板使用方法
2017/01/16 Javascript
jQuery轻松实现无缝轮播效果
2017/03/22 jQuery
vue项目关闭eslint校验
2018/03/21 Javascript
vue路由前进后退动画效果的实现代码
2018/12/10 Javascript
详解Vue中的基本语法和常用指令
2019/07/23 Javascript
javascrpt密码强度校验函数详解
2020/03/18 Javascript
jQuery实现的移动端图片缩放功能组件示例
2020/05/01 jQuery
JavaScript设计模式--简单工厂模式定义与应用案例详解
2020/05/23 Javascript
JavaScript arguments.callee作用及替换方案详解
2020/09/02 Javascript
[01:29]2017 DOTA2国际邀请赛官方英雄手办展示
2017/03/18 DOTA
Python中的super用法详解
2015/05/28 Python
Python编程argparse入门浅析
2018/02/07 Python
Python SMTP发送邮件遇到的一些问题及解决办法
2018/10/24 Python
python机器人运动范围问题的解答
2019/04/29 Python
基于Python快速处理PDF表格数据
2020/06/03 Python
解决Python安装cryptography报错问题
2020/09/03 Python
玩具反斗城美国官网:Toys"R"Us
2016/09/17 全球购物
Ellesse英国官网:意大利高级运动品牌
2019/07/23 全球购物
阿尔卡特(中国)的面试题目
2014/08/20 面试题
环保专业大学生职业规划设计
2014/01/10 职场文书
三方股东合作协议书范本
2014/09/28 职场文书
2015年体育部工作总结
2015/04/02 职场文书
浅谈:电影《孔子》观后感(范文)
2019/10/14 职场文书
扩展多台相同的Web服务器
2021/04/01 Servers
oracle重置序列从0开始递增1
2022/02/28 Oracle
BCL经典机 SONY ICF-5900W电路分析
2022/04/24 无线电