Python统计代码行与注释行数量的脚本实现
本文介绍如何使用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实现判断一行代码是否为注释及统计的方法即为全部内容,希望能提供参考,并欢迎大家支持。
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













