Python统计代码行与注释行数量的脚本实现

雨后青山
雨后青山
发布时间:2026-10-13| 7人浏览过
原创

本文介绍如何使用Python脚本统计代码文件中的代码行与注释行数量。通过解析单行与多行注释符号,利用标志位跟踪多行注释状态,并处理引号对内的注释符干扰,实现跨语言兼容的精准统计。

当前主流编辑器通常具备自动识别代码行与注释行的功能,但较少提供具体的行数统计支持,针对大量代码文件的代码行与注释行统计功能更是罕见。本文旨在通过一段Python脚本实现该目标,并尝试兼容对不同编程语言编写的代码进行统计。

注释符号的研究

首先分析常见语言的注释符号构成。通常注释符号分为单行注释符和多行注释符,以Python为例,分别对应#和'''(或""")。由于多行注释符会影响后续行的判断,因此在遍历各行时必须设置一个标志位multiCmtFlagIdx,用于记录是否已进入多行注释状态以及具体的多行注释符号类型。只有完成该判断,才能继续对后续字符进行分析。

1. 在多行注释中

此种情况下的后续分析相对简单。已知多行注释符类型后,可以判断后续字符中最早出现对应多行注释结束符的位置:

若能搜索到该结束符,则将multiCmtFlagIdx赋值为-1,表示多行注释已结束。若未搜索到,则说明本行后续字符仍处于多行注释中,可直接开始下一行的解析。

2. 不在多行注释中

针对此情况,若后续字符中除空格和制表符外,首先出现的是单行注释符,则注释符后的所有字符均属于注释内容,因此可直接结束本行解析并开始下一行。否则,需继续搜索多行注释开始符出现的位置。

找到多行注释开始符后,并不意味着其后即为注释内容,还需进行两项检查:

1)该注释符是否位于引号对内部,因为此时在引号中的注释符不生效;

2)该注释符是否为最早出现的多行注释开始符类型,因为同一种语言可能包含多种多行注释符,仅最早出现的那个起作用。

1)针对第一点,可在搜索起点至该注释符的区间内计算引号数量。若引号数量为偶数,说明不在引号对中;若为奇数,则说明在引号对中。

引号数量奇偶性判断需逐对进行,因为引号对内的引号不生效。存在一种特例:多行注释符本身也是引号的组合,例如Python。此时计算数量的引号类型应与搜索到的多行注释符不同,如多行注释符为''',则应计算"的数量。

2)针对第二点,可遍历各个多行注释开始符,并选取位置最靠前的开始符,随后查找其对应的结束符。

代码实现

\# encoding: utf-8
import re
'''
isCmt
功能:判断一行字符串是否为注释
输入:
 line: 字符串行
 isInMultiCmt:前面一行是否在多行注释中
 qttnFlagList: 引号列表
输出:
 isCmt: 当前行是否为注释
 isInMultiCmt:当前行是否在多行注释中
'''
def isCmt(line, multiCmtFlagIdx, cmtFlagObj):
 singleCmtFlag = cmtFlagObj["singleCmtFlag"] #单行注释符号
 multiCmtFlagList =cmtFlagObj["multiCmtFlagList"]
 qttnFlagList = cmtFlagObj["qttnFlagList"] #引号列表
 startPos = 0 #搜索多行注释符的开始位置
 isCmtRet = True
 # print 'line: ' + line.strip()
 while startPos < len(line): #查找注释符号直到行末
  if multiCmtFlagIdx == -1: #不在多行注释中
   minStartIdx = len(line) #搜索到最靠前的多行注释符
   if singleCmtFlag != '' and re.match(r'(\s)*' + singleCmtFlag, line[startPos:]): #单行注释
    break
   idx = 0
   preStartIdx = startPos #记录搜索多行注释符前的搜索位置
   while idx < len(cmtFlagObj["multiCmtFlagList"]):
    startCmtFlag = cmtFlagObj["multiCmtFlagList"][idx][0] #多行注释开始符号
    if startCmtFlag == '':
     return False, -1 #无多行注释符号
    try:
     startPos = re.search(r'(?<!\\)' + startCmtFlag, line[startPos:]).start() + startPos #找到多行注释开始符号
     if isInQuotation(line[:startPos], startCmtFlag, qttnFlagList): #注释开始符在引号中
      startPos += len(startCmtFlag.replace('\*', '*')) #找下一个多行注释开始符
      continue
     else: #注释符号不在引号中
      startPos += len(startCmtFlag.replace('\*', '*'))
      if startPos < minStartIdx:
       multiCmtFlagIdx = idx #是多行注释
       minStartIdx = startPos
      startPos = preStartIdx #找下一个多行注释开始符
      idx += 1
    except:
     idx += 1
     continue #没有找到多行注释开始符,继续查找下个类型的符号
   if minStartIdx != len(line): #此时搜索到了多行注释开始符
    startCmtFlag = cmtFlagObj["multiCmtFlagList"][multiCmtFlagIdx][0]
    if not re.match(r'(\s)*' + startCmtFlag, line[preStartIdx:]):
     isCmtRet = False
   elif line[preStartIdx:] != '\n':
    isCmtRet = False
   startPos = minStartIdx
  elif multiCmtFlagIdx != -1: #在多行注释中
   endCmtFlag = cmtFlagObj["multiCmtFlagList"][multiCmtFlagIdx][1] #多行注释开始符
   if endCmtFlag == '':
    return False, -1 #注释符号配置有错误
   try:
    startPos \
    = re.search(endCmtFlag, line[startPos:]).start() \
    + startPos \
    + len(endCmtFlag.replace('\*', '*')) #查找多汗注释结束符的位置
    multiCmtFlagIdx = -1
   except:
    break
 # print isCmtRet, multiCmtFlagIdx
 return isCmtRet, multiCmtFlagIdx #返回是否注释行,以及当前是否在多行注释中
'''
函数名:isInQuotation
功能:根据字符串中引号的奇偶,判断后面的字符是否在引号中
输入:
 line: 一行代码中指定字符前的字符串
 qttnFlagList: 引号列表
输出:
 布尔值:
  True:字符串包含在引号中
  False:字符串不包含在引号中
'''
def isInQuotation(line, cmtFlag, qttnFlagList):
 qttnFlagIdx = len(line)
 flagIdx = len(line)
 rearLine = line
 for i in range(len(qttnFlagList)):
  flag = qttnFlagList[i]
  if flag == cmtFlag[0]: #排除引号同时也是注释符号的情况
   continue
  try:
   flagIdx = re.search(r'(?<!\\)' + flag + r'.*', line).start() #查找左引号
   rearLine = re.search(r'(?<!\\)' + flag + r'.*', line).group()[len(flag):]
  except:
   flagIdx = len(line)
  if flagIdx < qttnFlagIdx: #根据最早出现的左引号,确认左引号类型
   qttnFlagIdx = flagIdx
   qttnFlag = flag
 if qttnFlagIdx != len(line):
  try:
   #print rearLine
   rearLine = re.search(r'(?<!\\)' + qttnFlag + r'.*', rearLine).group()[len(qttnFlag):] #查找右引号
   return isInQuotation(rearLine, cmtFlag[0], qttnFlagList) #再次查找下一个左引号
  except:
   return True #在引号对中
 else:
  return False #不在引号对中

以上关于Python实现判断一行代码是否为注释及统计的方法即为全部内容,希望能提供参考,并欢迎大家支持。

相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。