python统计项目代码行数

python

浏览数:1,306

2019-1-8


stat.py

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import chardet
import os
import sys

# 定义注释的格式
# dict的key表示文件的扩展名
# value包含3项,分别是单行注释的开头、多行注释的开头、多行注释的结尾
# 每一项为bytes或包含bytes的tuple

formats = {
    '.py': (b'#', (b'\'\'\'', b'"""'), (b'\'\'\'', b'"""')),
    '.pyw': (b'#', (b'\'\'\'', b'"""'), (b'\'\'\'', b'"""'))
}

def stat(path):

    # 检查输入的路径是一个文件还是一个文件夹
    # 如果是文件夹,则遍历其中所有的文件

    if os.path.isdir(path):
        paths = []

        for root, dirs, files in os.walk(path):
            paths += [os.path.join(root, f) for f in files]
    else:
        paths = [path]

    fn = 0 # 文件数量
    cl = 0 # 代码行数
    nl = 0 # 注释行数
    el = 0 # 空白行数
    tl = 0 # 合计行数

    for each in paths:

        # 检查文件的扩展名是否在支持的格式中,不在则跳过

        try:
            single, multi_start, multi_end = formats[os.path.splitext(each)[1]]
            fn += 1
        except:
            continue

        # 遍历文件的每一行
        # 此处文件以二进制模式打开,忽略编码信息

        with open(each, 'rb') as fp:
            data = fp.read()

        # 如果文件并非纯文本则跳过

        if chardet.detect(data)['encoding'] is None:
            continue

        # 去除BOM

        if data.startswith(b'\xef\xbb\xbf'):
            data = data[3:]

        in_note = False # 标记该行是否在多行注释中

        for line in data.splitlines():
            line = line.lstrip() # 去除行首的空白

            tl += 1

            if len(line) == 0:

                # 判断是否为空行

                el += 1
            elif line.startswith(single):

                # 判断是否为单行注释
                # 此处只检查该行是否只包含注释
                # 不统计行尾写有注释的代码行

                nl += 1
            elif in_note:

                # 判断是否包含在多行注释中

                nl += 1

                if line.endswith(multi_end):

                    # 判断多行注释是否结束

                    in_note = False
            elif line.startswith(multi_start):

                # 判断是否为多行注释的开头

                nl += 1
                in_note = True
            else:
                cl += 1

    return fn, cl, nl, el, tl

if __name__ == '__main__':
    try:
        path = sys.argv[1]
    except:
        path = __file__

    fn, cl, nl, el, tl = stat(path)

    print('项目名称:{path}\n文件数量:{fn}\n代码行数:{cl}\n注释行数:{nl}\n空白行数:{el}\n合计行数:{tl}'.format(**locals()))