从Python源代码中提取注释

LouYu

我正在尝试编写一个程序来提取用户输入的代码中的注释。我尝试使用正则表达式,但是发现它很难编写。

然后我在这里找到了一个帖子答案建议用来tokenize.generate_tokens分析语法,但是文档说

所述generate_tokens()发电机需要一个参数,readline,它必须是一个可调用的对象,它提供了相同的接口readline()的方法内置的文件对象(见文件对象)。

但是字符串对象没有readline方法。

然后我在这里找到了另一篇文章,建议StringIO.StringIO用于获取readline方法。所以我写了下面的代码:

import tokenize
import io
import StringIO

def extract(code):
    res = []
    comment = None
    stringio = StringIO.StringIO(code)
    for toktype, tokval, begin, end, line in tokenize.generate_tokens(stringio):
        # print(toknum,tokval)
        if toktype != tokenize.COMMENT:
            res.append((toktype, tokval))
        else:
            print tokenize.untokenize(toktype)
    return tokenize.untokenize(res)

并输入以下代码: extract('a = 1+2#A Comment')

但是得到了:

Traceback (most recent call last):     
   File "<stdin>", line 1, in <module>     
   File "ext.py", line 10, in extract     
     for toktype, tokval, begin, end, line in tokenize.generate_tokens(stringio):     
   File "C:\Python27\lib\tokenize.py", line 294, in generate_tokens     
     line = readline()     
AttributeError: StringIO instance has no `__call__` method

我知道我可以写一个新的类,但是还有更好的解决方案吗?

迪米特里斯·法萨拉基斯·希利亚德

回答更一般的情况(从模块,功能中提取):

模块:

该文档指定需要提供一个可调用对象,该可调用对象公开与readline()内置文件对象方法相同的接口这暗示:创建一个提供该方法的对象。

就模块而言,我们可以将open一个新模块作为普通文件并传入其readline方法。这是关键,您传递的参数methodreadline()

给出一个小scrpt.py文件:

# My amazing foo function.
def foo():
    """ docstring """
    # I will print
    print "Hello"
    return 0   # Return the value

# Maaaaaaain
if __name__ == "__main__":
    # this is main
    print "Main" 

我们将在处理所有文件时将其打开:

fileObj = open('scrpt.py', 'r')

现在,此文件对象具有一个称为readline(因为它是文件对象)的方法,我们可以安全地将该方法传递给它tokenize.generate_tokens并创建一个生成器。

tokenize.generate_tokens(仅tokenize.tokenize在Py3中-注意: Python 3需要readline返回,bytes因此您需要以'rb'模式打开文件)返回元素的命名元组,其中包含有关标记化元素的信息。这是一个小演示:

for toktype, tok, start, end, line in tokenize.generate_tokens(fileObj.readline):
    # we can also use token.tok_name[toktype] instead of 'COMMENT'
    # from the token module 
    if toktype == tokenize.COMMENT:
        print 'COMMENT' + " " + tok

注意我们如何将fileObj.readline方法传递给它。现在将打印:

COMMENT # My amazing foo function
COMMENT # I will print
COMMENT # Return the value
COMMENT # Maaaaaaain
COMMENT # this is main 

因此,无论位置如何,所有注释都会被检测到。当然不包括文档字符串。

职能:

如果没有open我真的想不到的情况,您可以实现类似的结果尽管如此,为了完整起见,我将提出另一种方法。在这种情况下,您将需要两个附加模块,inspect以及StringIOio.StringIO中的Python3):

假设您具有以下功能:

def bar():
    # I am bar
    print "I really am bar"
    # bar bar bar baaaar
    # (bar)
    return "Bar"

您需要一个类似文件的对象,该对象具有readline可以与结合使用方法tokenize好了,您可以使用来创建类似文件的对象,并可以str使用来代表函数的源在代码中:StringIO.StringIOstrinspect.getsource(func)

funcText = inpsect.getsource(bar)
funcFile = StringIO.StringIO(funcText)

现在,我们有了一个类似文件的对象,该对象表示具有所需readline方法的函数我们可以重新使用之前执行的循环,将其替换fileObj.readlinefuncFile.readline我们现在得到的输出具有相似的性质:

COMMENT # I am bar
COMMENT # bar bar bar baaaar
COMMENT # (bar)

顺便说一句,如果您真的想创建一种自定义方式来执行此操作,re请查看模块的源代码tokenize.py它定义了某些注释模式,(r'#[^\r\n]*')名称等,readline并在line列表中循环搜索样式。值得庆幸的是,经过一会儿:-),它并不太复杂。


功能答案extract(更新):

您已经创建了一个StringIO提供接口的对象,但是还没有将接口(readline传递tokenize.generate_tokens,而是传递了完整的对象(stringio

另外,在else子句中将TypeError引发a,因为untokenize期望可迭代作为输入。进行以下更改,您的功能可以正常工作:

def extract(code):
    res = []
    comment = None
    stringio = StringIO.StringIO(code)
    # pass in stringio.readline to generate_tokens
    for toktype, tokval, begin, end, line in tokenize.generate_tokens(stringio.readline):
        if toktype != tokenize.COMMENT:
            res.append((toktype, tokval))
        else:
            # wrap (toktype, tokval) tupple in list
            print tokenize.untokenize([(toktype, tokval)])
    return tokenize.untokenize(res)

提供表格形式expr = extract('a=1+2#A comment')输入后,该函数将打印注释并将表达式保留在expr

expr = extract('a=1+2#A comment')
#A comment

print expr
'a =1 +2 '

此外,正如我稍后提到的Python3io房屋StringIO,因此在这种情况下,import不需要它。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

从python源代码中提取完整的日志语句

在Yocto中提取Linux源代码的命令

如何从网页的源代码中提取URL?

如何从Jar文件中提取源代码?

从源代码字符串中提取Python函数源文本

Python - 使用通配符字符串匹配从网站的源代码中提取浮点数

在python中使用BeautifulSoup从url的源代码中提取特定部分下的文本

从网站源代码中提取特定的变化元素

使用RegEx从源代码中提取逗号分隔的单位

如何在OPENCV中提取与某些功能相关的源代码?

RegEx可以从HTML源代码中提取特定的URL格式

使用Qt Creator从网页的源代码中提取信息

如何通过xpath从scrapy的源代码中提取部分?

在 Python 中从 XML 文件中提取注释

C - 如何从代码文件中提取特定的注释行

用源代码注释Python函数调用的字符串

如何从Javascript代码中提取URL?-Python

用于从查询中提取数据的 Python 代码

从 HTML 注释中提取内容

从以url(... / image /../ 123.jpg)开头的源代码中提取完整图像url

从静态 C 库的源代码中提取函数定义以避免库编译

从给定的外部C#源代码中提取所有变量名

如何从PhantomJS中的DOM中提取一些源代码?

在 linux 命令行中从源代码中提取特定链接

如何使用正则表达式从 HTML 源代码中提取 JSON

从Java源代码中删除注释

源代码注释中的交叉引用

如何使用 Python + Selenium 从 HTML 代码中提取信息?

如何使用python从HTML代码中提取以“icon”开头的单词