Python实现判断一行代码是否为注释的方法

所属分类: 脚本专栏 / python 阅读数: 1094
收藏 0 赞 0 分享

目前的编辑器大都可以自动检测某一行代码是否为代码行或注释行,但并不太提供代码行/注释行行数的统计,对于大量代码文件的代码行/注释行统计,就更少见一些。本篇文章试用一段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实现按学生年龄排序的实际问题详解

这篇文章主要给大家介绍了关于Python实现按学生年龄排序实际问题的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面跟着小编来一起学习学习吧。
收藏 0 赞 0 分享

Python开发的HTTP库requests详解

Requests是用Python语言编写,基于urllib,采用Apache2 Licensed开源协议的HTTP库。它比urllib更加方便,可以节约我们大量的工作,完全满足HTTP测试需求。Requests的哲学是以PEP 20 的习语为中心开发的,所以它比urllib更加P
收藏 0 赞 0 分享

Python网络爬虫与信息提取(实例讲解)

下面小编就为大家带来一篇Python网络爬虫与信息提取(实例讲解)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
收藏 0 赞 0 分享

在python3环境下的Django中使用MySQL数据库的实例

下面小编就为大家带来一篇在python3环境下的Django中使用MySQL数据库的实例。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
收藏 0 赞 0 分享

Python 3.x读写csv文件中数字的方法示例

在我们日常开发中经常需要对csv文件进行读写,下面这篇文章主要给大家介绍了关于Python 3.x读写csv文件中数字的相关资料,文中通过示例代码介绍的非常详细,对大家具有一定的参考学习价值,需要的朋友们下面跟着小编来一起学习学习吧。
收藏 0 赞 0 分享

Python实现解析Bit Torrent种子文件内容的方法

这篇文章主要介绍了Python实现解析Bit Torrent种子文件内容的方法,结合实例形式分析了Python针对Torrent文件的读取与解析相关操作技巧与注意事项,需要的朋友可以参考下
收藏 0 赞 0 分享

Python实现文件内容批量追加的方法示例

这篇文章主要介绍了Python实现文件内容批量追加的方法,结合实例形式分析了Python文件的读写相关操作技巧,需要的朋友可以参考下
收藏 0 赞 0 分享

Python简单实现自动删除目录下空文件夹的方法

这篇文章主要介绍了Python简单实现自动删除目录下空文件夹的方法,涉及Python针对文件与目录的读取、判断、删除等相关操作技巧,需要的朋友可以参考下
收藏 0 赞 0 分享

简单学习Python多进程Multiprocessing

这篇文章主要和大家一起简单的学习Python多进程Multiprocessing ,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
收藏 0 赞 0 分享

Python导入模块时遇到的错误分析

这篇文章主要给大家详细解释了在Python处理导入模块的时候出现错误以及具体的情况分析,非常的详尽,有需要的小伙伴可以参考下
收藏 0 赞 0 分享
查看更多