python实验四 识别并提取Python程序中的类名、函数名、变量名等标识符。源码+详解

识别并提取Python程序中的类名、函数名、变量名等标识符。假设源文件的编写风格符合Python语言编程规范。
假设程序文件为FindIdentifiersFromPyFile.py,在命令提示符环境中使用命令“Python FindIdentifiersFromPyFile.py
目标文件名”查找并输出目标文件中的标识符。

import re  # 导入re模块
import os  # 导入os模块
import sys # 导入sys模块

classes = {}  # 定义一个类,其类名为空
functions = []  # 定义一个列表,列表里为空
variables = {'normal': {}, 'parameter': {}, 'infor': {}}  # 定义一个字典其中键的值为normal、parameter、infor为形参{}存放相应的值
'''This is a test string:
atest,btest=3,5
to verify that variables in comments will be ignored by this algorithm
'''  # 用来提示信息,测试字符序列用来验证注释中的变量将被此算法忽略,来验证注释的准确性


def _identifyClassNames(idex, line):  # 定义一个函数,此函数有两个形参
    ''':parameter index is the line number of line,
    :parameter line is a line of code of the file to check
    '''  # 形参parameter、index是line的行号,参数索引用于检查文件
    pattern = re.compile(
        r'(?<=class\s)\w+(/=.*?:)$')  # 定义一个对象并用正则表达式,其中这个正则表达式表示如果“=”后面的字符出现则匹配,class子模板以ls
    # 匹配任何字符以数字,字符或下划线开头,以若是"="前面出现的字段则匹配反之亦然为字段结尾
    matchResult = pattern.serch(line)  # 定义一个变量并用pattern访问search方法来进行初始化
    if not matchResult:  # 调用if语句进行判断mathResul的值是否正确
        return  # 返回语句
    className = matchResult.group(0)  # 定义一个变量并进行初始化,对象方法来进行
    classes[className] = classes.get(className, [])  # 定义一定空间的列表用对象get方法来对其初始化
    classes[className].append(index)  # 调用列表名方法来用append()进行追加


def _indetifyFunctionNames(index, line):  # 定义一个函数该函数有形参
    pattern = re.compile(
        r'(?<=def\s)(\w+)\((.*$?)\)(?=:)$')  #
    # 定义一个变量并调用正则表达式对其初始化,该正则表达式的含义是以如果“=”后面的字符出现则匹配反之或以匹配数字、字母、下划线只匹配一个字符为行首以除换行符出现0次或多次匹配一个字符式后面的字符出现则匹配为行尾
    matchResult = pattern.search(line)  # 定义一个变量,并用pattern访问,search方法来进行初始化
    if not matchResult:  # 调用if语句进行判断,matchResult的值是否正确
        return  # 返回语句
    functionName = matchResult.group(1)  # 定义一个变量并进行初始化,通过对象方法来对其初始化
    functions.append((functionName, index))  # 调用append方法由于函数的形参有两个须与方法参数保持一致
    parameters = matchResult.group(2).split(r',')  # 调用对象的第二个元素的split方法以,分隔
    if parameters[0] == '':  # 调用if语句,判断parameters的第一个列表元素是否为空
        return  # 返回语句
    for v in parameters:  # for循环
        variables['parameter'][v] = variables['parameter'].get(v, [])  # 调用variables第一个参数来访问get()方法对variables形参的列表初始化
        variables['parameter'][v].append(index)  # 调用对象的append进行元素追加


def _identifyVariableNames(index, line):  # 定义一个函数,该函数有两个参数
    # find normal variables ,including the case:a,b =3,5
    pattern = re.compile(r'\b(.*?)(?=\s=)$')  # 定义一个变量并用正则函数表达式表示以单词类或单词尾r开头出现0或1次为行首,以空白字符为行尾
    matchResult = pattern.search(line)  # 定义一个变量,并用pattern,search()对其初始化
    if matchResult:  # 调用if语句,进行判断
        vs = matchResult.group(1).split(r', ')  # 定义一个变量vs,并用对象split()以","对其进行分隔
        for v in vs:  # 进入for循环
            # consider the case 'if variable == value'
            if 'if' in v:  # if判断语句,是否在v集合中
                v = v.split()[1]  # 调用split()方法,对变量v进行初始化
            # consider the case :'a[3]=3'
            if '[' in v:  # 判断'['是否在v中
                v = v[0:v.index('[')]  # 调用index()方法,访问第一个元素并存取
            variables['normal'][v] = variables['normal'].get(v, [])  # 调用对象get()来对variables['normal'][v]初始化
            variables['normal'][v].append(index)  # 调用append()方法进行追加
    # find the variables in for statements
    pattern = re.compile(
        r'(?<=for\s)(,*?)(?=\sin)$')  # 定义一个变量并用正则表达式,其中这个正则表达式表示以r开头或结尾的,对比后面的字符出现则匹配为行首,以出现0或1次的空字符或看是否出现0或多次sin为行首
    matchResult = pattern.search(line)  # 调用search()进行初始化
    if matchResult:  # 判断matchResult是否合理
        vs = matchResult.group(1).split(r', ')  # 对marchResult的第一个元素进行处理,以","作为分隔
        for v in vs:  # for循环
            variables['infor'][v] = variables['infor'].get(v, [])  # 调用get()对其初始化
            variables['infor'][v].append(index)  # 调用append()方法进行追加


def output():  # 定义一个方法
    print('=' * 30)  # 调用print()其中'='表示如果后面的字符出现则匹配,匹配30位任意字符,反之为空
    print('The class names and their line numbers are:')  # 输出提示信息
    for key, value in classes.items():  # for循环
        print(key, ':', value)  # 输出键和值
        print('=' * 30)  # 调用print()其中'='表示如果后面的字符出现则匹配,匹配30位任意字符,反之为空
        print('The function names and their line numbers are:')  # 输出提示信息
        for i in functions:  # for循环
            print(i[0], ':', i[1])  # 输出其字典的键和值
        print('=' * 30)  # 调用print()其中'='表示如果后面的字符出现则匹配,匹配30位任意字符,反之为空
        print('The normal variable names and their line numbers are:')  # 输出提示信息
        for key, value in variables['parameter'].items():  # for循环
            print(key, ':', value)  # 输出键和值
        print('=' * 20)  # 调用print()其中'='表示如果后面的字符出现则匹配,匹配20位任意字符,反之为空
        print('The parameter names and their line numbers in functions are:')  # 输出提示信息
        for key, value in variables['infor'].items():  # for循环
            print(key, ':', value)  # 输出键和值


# suppose the lines of comments less than 50
def comments(index):  # 定义一个函数,index为形参
    for i in range(50):  # for循环
        line = allLines[index + i].strip()  # 调用allLines[]求得行数
        if line.endswith('"""') or line.endswith("'''"):  # 调用if语句判断
            return i + 1  # 返回i值+1


if __name__ == '__main__':  # 脚本独立运行,则其__name__属性值被自动设置为'__main__'
    fileName = sys.argv[1]  # 定义一个变量,并调用argv[]对其初始化
    if not os.path.isfile(fileName):  # 判断操作系统的路径名是不是fileName
        print('Your input is not a file.')  # 输出提示信息
        sys.exit(0)  # 退出if语句
    if not fileName.endswith(('.py', '.pyw')):  # 判断fileName以.py或.pyw结尾的文件
        print('Sorry.I can only check Python source file.')  # 输出提示信息
        sys.exit(0)  # 退出if语句
    allLines = []  # 此时allLines为空的列表
    with open(fileName, 'r') as fp:  # 如果读取不存在以'r'的文件,则会出现error错误提示
        allLines = fp.readlines()  # 调用readlines()方法来读取fp行数返回给它
    index = 0  # 此时索引为0
    totalLen = len(allLines)  # 调用len()求出allLines的长度
    while index < totalLen:  # 调用while语句判断index位置合理
        line = allLines[index]  # 定义一个变量求出allLines当前位置
        # strip the blank characters at both end of line
        line = line.strip()  # 进行line打包处理
        # ignore the comments starting with '#'
        if line.startswith('#'):  # if语句判断line是否以#开头
            index += 1  # index=index+1
            continue  # 退出当前循环
        # ignore the comments between ''' or """
        if line.startswith('"""') or line.startswith("'''"):  # if语句判断
            index += comments(index)  # index=index.comments(index)
            continue  # 退出当前循环
    # identify identifiers
    _identifyClassNames(index + 1, line)  # 调用函数实现语句
    _indetifyFunctionNames(index + 1, line)  # 调用FunctionNames()函数实现下标的索引转换
    _identifyVariableNames(index + 1, line)  # 调用VariableNames()函数实现下标的增减转换
    index += 1  # index=index+1
output()  # 退出爬虫

上一篇:FastIo声明和定义


下一篇:Java || 看了大二学长写的代码,我竟开始默默的模仿了。。。