使用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模拟新浪微博登陆功能(新浪微博爬虫)
Dec 24 Python
从零学Python之hello world
May 21 Python
跟老齐学Python之数据类型总结
Sep 24 Python
跟老齐学Python之编写类之四再论继承
Oct 11 Python
详解python进行mp3格式判断
Dec 23 Python
Python实现文件信息进行合并实例代码
Jan 17 Python
Python设计模式之建造者模式实例详解
Jan 17 Python
python库matplotlib绘制坐标图
Oct 18 Python
利用python实现.dcm格式图像转为.jpg格式
Jan 13 Python
python实现tail -f 功能
Jan 17 Python
Python tornado上传文件的功能
Mar 26 Python
Python3+Appium安装及Appium模拟微信登录方法详解
Feb 16 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
php中unlink()、mkdir()、rmdir()等方法的使用介绍
2012/12/21 PHP
php禁用函数设置及查看方法详解
2016/07/25 PHP
Jquery.Form 异步提交表单的简单实例
2014/03/03 Javascript
javascript实现阻止iOS APP中的链接打开Safari浏览器
2014/06/12 Javascript
用javascript关闭本窗口不弹出询问框的方法
2014/09/12 Javascript
用原生JS获取CLASS对象(很简单实用)
2014/10/15 Javascript
深入理解JavaScript系列(40):设计模式之组合模式详解
2015/03/04 Javascript
js实现仿百度汽车频道选择汽车图片展示实例
2015/05/06 Javascript
jQuery 3.0 的变化及使用方法
2016/02/01 Javascript
vue后台管理之动态加载路由的方法
2018/08/13 Javascript
javascript 使用sleep函数的常见方法详解
2020/04/26 Javascript
Python实现的彩票机选器实例
2015/06/17 Python
python验证码识别的实例详解
2016/09/09 Python
Python从零开始创建区块链
2018/03/06 Python
python数据结构学习之实现线性表的顺序
2018/09/28 Python
对Python中for复合语句的使用示例讲解
2018/11/01 Python
Ubuntu+python将nii图像保存成png格式
2019/07/18 Python
Django 在iframe里跳转顶层url的例子
2019/08/21 Python
使用Python生成200个激活码的实现方法
2019/11/22 Python
Python使用requests xpath 并开启多线程爬取西刺代理ip实例
2020/03/06 Python
python实现最速下降法
2020/03/24 Python
Python依赖包迁移到断网环境操作
2020/07/13 Python
python/golang 删除链表中的元素
2020/09/14 Python
python中四舍五入的正确打开方式
2021/01/18 Python
HTML5 的新的表单元素(datalist/keygen/output)使用介绍
2013/07/19 HTML / CSS
可口可乐唇膏:Lip Smackers
2019/08/27 全球购物
使用索引有什么好处
2016/07/27 面试题
圣诞节红领巾广播稿
2014/02/03 职场文书
一名老师的自我评价
2014/02/07 职场文书
大四自我鉴定
2014/02/08 职场文书
党员领导干部廉洁从政承诺书
2014/03/27 职场文书
好书伴我成长演讲稿
2014/05/14 职场文书
浪漫的婚礼主持词
2015/06/30 职场文书
《七月的天山》教学反思
2016/02/19 职场文书
mysql 数据插入优化方法之concurrent_insert
2021/07/01 MySQL
JavaScript中MutationObServer监听DOM元素详情
2021/11/27 Javascript