读取项目目录,并统计代码行数、注释行数和空行行数
自己的想法
刚看到这个时候还没觉得多难,结果做起来发现被如何很好地判断单行注释以及多行注释给为难了很久。
又想要尽量地实现代码复用,所以翻看了一些关于类继承的说明,把自己的思路弄的更乱了。
看到句话,编程的黄金准则“先能工作,要更好,变更快”。所以把代码分成了几个部分写。
单个代码文件的读取
代码、注释和空行的判断
在逐行读取过程中加入对多行注释判断的flag
对目录内的代码文件的逐个读取
以上几点都完成后,再使用类定义和继承还有方法的改写实现代码的复用。
关于2、3两点各位都有自己的思路,因此我不多说。主要总结在解决1、2问题时使用的新的函数或是方法。
文件读取
使用open()函数读取文件时,如果读取到的行为None,那么它会将该行中的'\n', '\r', or '\r\n'都改写为'\n'后再返回;如果读取到的是' ',那么返回值最后的字符不会被转换,也就是如果是回车换行的话会返回'\n',但是整行都是空格的话是不会有'\n'的。
因此对空白行的判断是以'\n'和空格两者为准的。
目录文件的遍历
一开始时候想要自己造个轮子进行遍历,试着用了深度优先搜索,然后由于某种未知原因,程序运行的时间不敢恭维。。。不过这个过程中学习了几个新的方法
返回一个DirEntry类,其中包含了目录内的文件和文件夹(不会向文件夹的深处继续遍历);相比于方法os.listdir()的优势在于其返回的类型可以做更多的操作,比如获取文件类型、判断其中的元素是目录还是文件等。
其内置的方法和属性便于对文件或是文件夹进行处理
name:返回该对象的名称
path:返回该对象的绝对路径
is_file():判断该对象是否为文件,是则返回True,否则返回False
is_dir():判断该对象是否为文件目录,是则返回True,否则返回False
不造轮子了
介绍下os模块
提供了一些基于操作系统的便捷功能,因此在不同操作系统上的实现方法并不相同。
并且,官方还友情提示了以下几点:
- 想对文件进行处理参看open()
- 想对文件路径进行处理参看os.path()
- 想对所有文件中的所有行进行处理参看fileinput()
- 想要新建目录或者文件夹参看tempfile
- 更高级的对文件和文件目录的操作参看shuti
这是我用到的os.walk(path, topdown=True, onerror=None, followlinks=False)
由path开始进行遍历,广度优先,对每个文件夹(包括根目录)都会返回一个三元的tuple,其中包含(dirpath, dirnames , filenames)
参数中的topdown是一个决定优先生成根目录的tuple还是优先生成子目录的tuple的参数;为True即自顶向下,为False则自向上。
提供了一些对路径进行处理的函数
os.path.join(path, *paths):将两个参数智能地合成一个可用的路径,每个参数之间都会添加一个目录分隔符
os.path.dirname(path):返回路径下的文件夹名称
os.path.exists(path):若该路径存在或指向一个文件,返回True
os.path.getsize(path):返回路径指向对象的大小,以bits为单位
os.path.isfile(path):当路径指向的文件存在时返回True
os.path.isdir(path):当路径指向的目录存在时返回True
os.path.split(path):将path分为head和tail两个部分,其中tail为path的最后一个内容,head则是其余的所有内容
放上自己的代码
emmmm,发现漏了统计文件数目了,不过这个的实现并不困难。
import os
class Project:
def __init__(self, direct, suffix, one_comment_symbol, inline_comment_symbol, long_comment_symbol):
self.direct = direct
self.suffix = suffix
self.one_comment_symbol = one_comment_symbol
self.inline_comment_symbol = inline_comment_symbol
self.long_comment_symbol = long_comment_symbol
self.codes, self.comments, self.blanks, self.project_files = self.project_check()
@staticmethod
def is_blank(line):
if line == '' or line == '\n':
return True
else:
return False
def is_codes(self, line):
if line == '' or line == '\n':
return False
if line.startswith(self.one_comment_symbol) or line.startswith(self.long_comment_symbol):
return False
if line == ' ' or line == '\n':
return False
else:
return True
def is_comment(self, line):
beg, end, flag = False, False, False
if line.startswith(self.long_comment_symbol):
beg = True
if line.endswith(self.long_comment_symbol):
end = True
if beg and end:
flag = True
if line == self.long_comment_symbol:
flag = True
if line.startswith(self.one_comment_symbol) or self.inline_comment_symbol in line:
flag = True
return flag
def file_check(self, path, codecount=0, blankcount=0, commentcount=0):
with open(path, encoding='utf-8') as f:
long_comment_flag = False
for line in f:
line = line.strip()
blank_flag = self.is_blank(line)
code_flag = self.is_codes(line)
comment_flag = self.is_comment(line)
if long_comment_flag: # 多行注释时只需考虑注释何时结束
if line == self.long_comment_symbol:
long_comment_flag = False
commentcount += 1
else: # 非多行注释时考虑多行注释是否开始,是否是单行注释,是否是代码段,是否是空行
if line == self.long_comment_symbol:
long_comment_flag = True
if comment_flag:
commentcount += 1
if code_flag:
codecount += 1
if blank_flag:
blankcount += 1
return codecount, commentcount, blankcount
def project_check(self):
codes = 0
comments = 0
blanks = 0
project_files = dict()
for dirpath, direc, files in os.walk(self.direct):
for file in files:
if self.suffix in file.split('.'):
file_path = os.path.join(dirpath, file)
code, comment, blank = self.file_check(file_path)
codes += code
comments += comment
blanks += blank
project_files.setdefault(file, [code, comment, blank]) # 在project中若出现同名文件则会有问题
return codes, comments, blanks, project_files
def file_view(self, filename):
file = self.project_files[filename]
print(filename + ':' + '\n' +
'code' + str(file[0]) + ' ' + 'comment' + str(file[1]) + ' ' + 'blank' + str(file[2]))
class Pyproject(Project):
def __init__(self, direct, suffix='py', one_comment_symbol='#', inline_comment_symbol=' # ', long_comment_symbol="'''"):
super(Pyproject, self).__init__(direct, suffix, one_comment_symbol, inline_comment_symbol, long_comment_symbol)
def is_codes(self, line):
Project.is_codes(self, line)
# super(Pyproject, self).is_codes(line)
def is_comment(self, line):
Project.is_comment(self, line)
# super(Pyproject, self).is_comment(line)
project = Project('D:\python', suffix='py', one_comment_symbol='#', inline_comment_symbol=' # ', long_comment_symbol="'''")
print(project.codes, project.comments, project.blanks)
project.file_view('day_6.py')