使用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实现获取客户机上指定文件并传输到服务器的方法
Mar 16 Python
python3抓取中文网页的方法
Jul 28 Python
解决python爬虫中有中文的url问题
May 11 Python
基于python的ini配置文件操作工具类
Apr 24 Python
计算机二级python学习教程(3) python语言基本数据类型
May 16 Python
Django Form 实时从数据库中获取数据的操作方法
Jul 25 Python
pytorch 自定义卷积核进行卷积操作方式
Dec 30 Python
pytorch 实现在预训练模型的 input上增减通道
Jan 06 Python
python GUI框架pyqt5 对图片进行流式布局的方法(瀑布流flowlayout)
Mar 12 Python
Tensorflow中的dropout的使用方法
Mar 13 Python
Python2手动安装更新pip过程实例解析
Jul 16 Python
Python截图并保存的具体实例
Jan 14 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
javascript 对象比较实现代码
2009/04/27 Javascript
Javascript中valueOf与toString区别浅析
2013/03/19 Javascript
jquery插件冲突(jquery.noconflict)解决方法分享
2014/03/20 Javascript
JavaScript中的prototype.bind()方法介绍
2014/04/04 Javascript
javascript的tab切换原理与效果实现方法
2015/01/10 Javascript
详细解读JavaScript的跨浏览器事件处理
2015/08/12 Javascript
Node.js编写CLI的实例详解
2017/05/17 Javascript
实现微信小程序的wxml文件和wxss文件在webstrom的支持
2017/06/12 Javascript
ionic2屏幕适配实现适配手机、平板等设备的示例代码
2017/08/11 Javascript
原生JS实现小小的音乐播放器
2017/10/16 Javascript
通过nodejs 服务器读取HTML文件渲染到页面的方法
2018/05/17 NodeJs
jquery 动态遍历select 赋值的实例
2018/09/12 jQuery
laydate时间日历插件使用方法详解
2018/11/14 Javascript
微信小程序日历效果
2018/12/29 Javascript
jQuery访问json文件中数据的方法示例
2019/01/28 jQuery
layer关闭弹出窗口触发表单提交问题的处理方法
2019/09/25 Javascript
Vue.js桌面端自定义滚动条组件之美化滚动条VScroll
2020/12/01 Vue.js
[48:29]2018DOTA2亚洲邀请赛3月30日 小组赛A组 LGD VS KG
2018/03/31 DOTA
[05:00]TI9战队采访 - Royal Never Give Up
2019/08/20 DOTA
[02:29]大剑、皮鞭、女装,这届DOTA2勇士令状里都有
2020/07/17 DOTA
python实现定时提取实时日志程序
2018/06/22 Python
Python常见的pandas用法demo示例
2019/03/16 Python
python机器人运动范围问题的解答
2019/04/29 Python
Python学习笔记之变量、自定义函数用法示例
2019/05/28 Python
Django 自定义404 500等错误页面的实现
2020/03/08 Python
精油和天然健康美容产品:Art Naturals
2018/01/27 全球购物
中英文求职信范文
2014/01/27 职场文书
担保书怎么写
2014/04/01 职场文书
英语故事演讲稿
2014/04/29 职场文书
报考公务员诚信承诺书
2014/08/29 职场文书
毕业证代领委托书
2014/09/26 职场文书
公司停电通知
2015/04/15 职场文书
七年级写作指导之游记作文
2019/10/07 职场文书
Python离线安装openpyxl模块的步骤
2021/03/30 Python
Python带你从浅入深探究Tuple(基础篇)
2021/05/15 Python
Go语言特点及基本数据类型使用详解
2022/03/21 Golang