Python实现一个代码行数统计工具(易拓展到其他语言版)

前情提要及单种语言的代码行统计思路,详见我另一篇文章:Python实现一个代码行数统计工具(以C/C++为例)
关于如何达到容易拓展到其他语言的效果,我想到的方法是用列表将不同语言的续行符、注释符、字符串符存起来,靠文件后缀来确定该用哪种符号。这只是我自己的一种思路,但感觉思路很一般,有想法的读者们可以进一步的优化。
具体代码如下:

from queue import Empty
import sys
import os
from enum import Enum
import time
from unittest.mock import patch
import threading

class Counter:

    Line_numbers = 0
    Code = 0
    total_comment_numbers = 0
    Blanks = 0
    # -------------------------------------------------------------------------
    # 扩展到其他语言代码统计时需要维护的代码块
    extendList = [".h", ".cpp", ".hpp", ".rb"] # 不同语言代码文件扩展名列表
    # -------------------------------------------------------------------------
    def get_filelist(dir, Filelist):
        # 获取当前目录下所有子目录及所有cpp文件
        newDir = dir
        dirList = []
        
        if os.path.isfile(dir) and os.path.splitext(dir)[1] in Counter.extendList:
            #文件扩展名属于列表中其中一种时,文件路径添加到filelist中
            Filelist.append(dir)
        
        # 路径为目录时,遍历目录下的所有文件和目录
        elif os.path.isdir(dir):
            for s in os.listdir(dir):
                newDir=os.path.join(dir, s)
                Counter.get_filelist(newDir, Filelist)
            
        return Filelist


    def CodeCounter(filename, path):
        codes_numbers = 0
        empty = 0
        comment_numbers = 0
        
        extendIdx =  Counter.extendList.index(os.path.splitext(filename)[1])
        
        # -------------------------------------------------------------------------
        # 扩展到其他语言代码统计时需要维护的代码块,各标志符列表下标与源代码文件后缀列表(Counter.extendList)下标一致
        
        LineCommentSymbol = ["//", "//", "//", "#"] # 进入行注释标识
        BlockCommentSymbol = ["/*", "/*", "/*", "=begin"] # 进入块注释标识
        ExitBlockCommentSymbol = ["*/", "*/", "*/", "=end"] # 退出块注释标识
        CharStringSymbol = [["\""], ["\""], ["\""], ["\"", "\'"]] # 进入字符串标识
        CombinationSymbol = ["\\", "\\", "\\", "\\"] # 续行符标识
        # -------------------------------------------------------------------------
        
        # 打开文件并获取所有行
        fp = open(filename, encoding = 'gbk', errors = 'ignore')
        lines = fp.readlines()
        
        row_cur_status = Status.Common # 设置初始状态为Common
        temp = ""
        
        for line in lines:
            line = temp + line
            line = line.strip("\r\t ")
            if line[-len(CombinationSymbol[extendIdx]) - 1:] == CombinationSymbol[extendIdx]: # 检查末尾是否有续行符,若有续行符,则保存当前line值,准备与下一行进行拼接
                temp += line[:-len(CombinationSymbol[extendIdx]) - 1]
                continue
            else:
                temp = ""
            
            lineLen = len(line)
            
            if lineLen == 1 and line == '\n':
                #空行,空行数量+1
                empty += 1
                # f.write('\n')
                continue
            
            skipStep = 0 # 需要跳过的字符数,用于跳过一些符号,例如遇到//时进入行注释状态,跳过到//后面第一个字符
            is_effective_code = False # 有效代码行标识
            
            for i in range(lineLen):
                
                if skipStep != 0:
                    skipStep -= 1
                    continue
                
                if row_cur_status == Status.Common:
                    # 普通状态下
                    
                    for symbol in CharStringSymbol[extendIdx]:
                        #检查是否进入字符串模式
                        symbolLen = len(symbol)
                        if(i + symbolLen > lineLen):
                            continue
                        if line[i:i + symbolLen] == symbol:
                            is_effective_code = True
                            row_cur_status = Status.CharString # 切换到字符串状态
                            CharStringStart = symbol # 记录字符串开始时的标识符,用于判断后续退出位置
                            break
                        
                    if row_cur_status != Status.Common:
                        continue
                    
                    # 检查是否进入行注释状态
                    symbol = LineCommentSymbol[extendIdx]
                    symbolLen = len(symbol)
                    if (i + symbolLen <= lineLen) and line[i:i + symbolLen] == symbol:
                        row_cur_status = Status.LineComment # 切换到行注释状态
                        skipStep = symbolLen - 1
                        continue
                        
                    # 检查是否进入块注释状态
                    symbol = BlockCommentSymbol[extendIdx]
                    symbolLen = len(symbol)
                    if (i + symbolLen <= lineLen) and line[i:i + symbolLen] == symbol:
                        row_cur_status = Status.BlockComments # 切换到块注释状态
                        skipStep = symbolLen - 1
                        continue
                    
                    if line[i] == '\n':
                        continue
                    if line[i] == ' ':
                        continue
                    else:
                        is_effective_code = True # 代码行有效
                        continue
                    
                elif row_cur_status == Status.CharString:
                    #字符串状态下
                    if line[i:i + len(CharStringStart)] == CharStringStart:
                        row_cur_status = Status.Common # 字符串结束,切换回普通状态 
                        skipStep = len(CharStringStart) - 1
                        # is_effective_code = True
                        continue
                    else:
                        continue
                    
                elif row_cur_status == Status.BlockComments:
                    # 块注释状态下
                    symbol = ExitBlockCommentSymbol[extendIdx]
                    symbolLen = len(symbol)
                    if (i + symbolLen <= lineLen) and line[i:i + symbolLen] == symbol:
                        # 退出块注释,注释行加上块注释的最后一行,切换回普通状态  
                        comment_numbers += 1
                        row_cur_status = Status.Common
                        skipStep = symbolLen - 1
                        continue
                    else:
                        continue

            
            # 单行遍历结束后,以当前状态记录行数
            # 代码行有效,有效代码行数+1
            if is_effective_code == True:
                codes_numbers += 1
            
            # 当前状态为块注释或行注释状态下,注释代码行数+1
            if row_cur_status in (Status.BlockComments, Status.LineComment):
                comment_numbers += 1
            
            # 当前状态不为块注释时,进入下一行前,初始化当前状态
            if row_cur_status != Status.BlockComments:
                row_cur_status = Status.Common
        
        total = len(lines)        
        
        if(lines[-1][-1] == '\n'):
            total += 1
            empty += 1
            

        fp.close()
        # f.close()
        
        print("file:{0} total:{1} empty:{2} effective:{3} comment:{4}               effective:{3}".format(filename.replace(path + "\\", ""), total, empty, codes_numbers, comment_numbers))
        
        Counter.Line_numbers += total
        Counter.Blanks += empty
        Counter.Code += codes_numbers
        Counter.total_comment_numbers += comment_numbers
        


if __name__ == "__main__":
    path = os.path.abspath(sys.argv[1]) #获取命令行输入的文件夹绝对路径
    # path = r"C:\Users\Undefined\Desktop\test\Osiris"
    list = Counter.get_filelist(path, [])
    threads = []
    
    # 将可能遇到的情况枚举
    # Common:表示普通状态 
    # CharString:表示字符串状态 
    # LineComment:表示行注释状态 
    # BlockComments:表示块注释状态 
    Status = Enum('Status','Init Common CharString LineComment BlockComments')
    
    for file in  list:
        t = threading.Thread(target=Counter.CodeCounter,args=(file, path))
        threads.append(t)
        

    for thr in threads:
    thr.start()

    for the in threads:    
    thr.join()

    time.sleep(0.1)
    
    print("-"*56)
    print("- {0:<10} {1:<10} {2:<10} {3:<10} {4:<10}".format("Files", "Lines", "Code", "Comments", "Blanks"))
    print("-"*56)
    print("  {0:<10} {1:<10} {2:<10} {3:<10} {4:<10}".format(len(list), Counter.Line_numbers, Counter.Code, Counter.total_comment_numbers, Counter.Blanks))
    print("-"*56)
    

若文中有错误,还请大佬在评论区指正,我会好好学习和改进,谢谢大佬们🙇

  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
统计代码工具Kazoeciao.支持各种语言,需要到官网下载插件包. 官网:https://www.vector.co.jp/soft/winnt/prog/se251853.html 「かぞえチャオ!」は、ソフト開発における、規模見積りから生産性評価にまで使える非常に便利なステップカウンタです。 ソースコードのステップ数のカウントのほか、変更前後のソースコードのステップ比較、指定キーワードのカウント、市販の静的解析ツールと連携した警告数のカウントができます。 これらのカウントは、ファイル単位だけでなく、クラス単位やメソッド(関数)単位でもできます。 Shift-JIS、EUC、JIS、UTF-8、UTF-16(LE/BE)のステップカウント、ステップ比較に対応しています。 ステップ比較では、新規、修正元、修正、流用、削除ステップ数の算出ができます。 HTMLファイル内のスクリプト部分のカウントにも対応しています。 カウント結果は、CSV、HTML、TXT形式のファイルとして保存できます。 拡張子個別情報ファイルを追加することにより、さまざまな言語で記述されたプログラムのステップカウントに対応できます。 標準で、C,C++,Java,Visual Basic,MASM に対応しています。 その他の言語も、専用サイト「チャオの部屋」でサポートします。 操作は簡単!ややこしい設定は一切ありません!
Python代码统计工具有很多种,以下是其中几种常用的工具: 1. cloc:cloc是一款开源的多语言代码统计工具,可以统计各种编程语言代码数,包括Python。它可以生成详细的代码统计报告,包括代码数、空数、注释数等。使用cloc,您可以通过命令或者图形界面界面来统计Python代码数。 2. Pygount:Pygount是一个基于Python代码统计工具,它可以统计各种编程语言代码数,包括Python。Pygount提供了一个简单用的命令界面,可以输出代码数的统计结果。 3. SLOCCount:SLOCCount是一个流代码统计工具,可以统计多种编程语言代码数。它可以生成详细的代码统计报告,包括代码数、空数、注释数等。SLOCCount可以通过命令界面或者图形界面来统计Python代码数。 4. Radon:Radon是一个Python代码复杂性分析工具,它也可以用来统计代码数。Radon提供了各种度量方法,包括LOC (Lines of Code)、LLOC (Logical Lines of Code)、SLOC (Source Lines of Code)等,可以帮助您更全面地了解代码的复杂性和数。 以上是几种常用的Python代码统计工具,您可以根据自己的需求和喜好选择适合的工具使用。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [Python实现代码统计工具](https://blog.csdn.net/weixin_30664539/article/details/99054675)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [chatgpt赋能pythonPython代码统计-统计Python代码数的常用工具与使用方法](https://blog.csdn.net/findyi123/article/details/130980303)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值