【问题标题】:How to parse a python Loops using a python script?如何使用 python 脚本解析 python 循环?
【发布时间】:2013-06-11 18:57:34
【问题描述】:

我的主要目标是解析 python 循环,以便我可以插入一些语句进行分析。

Normal code:
#A.py

[code Starts]
.
.
.
while [condition]:
    [statements]
    [statements]
    [statements]

.
.
.
[code ends]

仪表代码:

Normal code:
#A.py

[code Starts]
.
.
.
count =0                                    <---------- inserted code 
print "Entry of loop"                       <---------- inserted code
while [condition]:
    print "Iteration Number " + count++     <---------- inserted code
    [statements]
    [statements]
    [statements]
print "Exit of loop"                        <---------- inserted code
.
.
.
[code ends]

我的目标是将上述代码以适当的缩进方式插入到适当的位置。该循环也可以是一个 for 循环。为了实现上述检测代码,我需要解析 A.py 文件中的循环并插入这些代码。

有没有一种好方法可以解析这些循环并获取循环的行号以便我可以检测?

谢谢

【问题讨论】:

  • 您尝试过使用ast 模块吗?这个任务与your previous question非常相似。
  • @Janne Karila 是的,我实际上需要完全像我在上一个问题中所做的那样。但由于我从未使用过 ast 我不知道要使用什么功能。如果你能发布一个简单的场景,你会很好吗?
  • 假设您解析文件,您将如何识别要检测的循环,还是全部检测?
  • @chepner 我会全部使用。这是我的要求
  • 您只想要模块级别的循环吗?例如在if some condition: for elem in iterable: do stuff 中是否要添加内部for 的代码?你介意嵌套循环吗?你想处理单行循环(例如for x in a: print x)吗?在最简单的情况下,逐行读取文件并在需要时输出额外的行应该很容易,否则您必须进行更多解析。

标签: python parsing loops instrumentation


【解决方案1】:

解析通常是一项艰巨的任务。 您可以使用Pygments python 库,它是一个语法高亮库。 这可能看起来与您打算做的不同,但事实并非如此。毕竟,着色代码基本上是在代码块中添加颜色信息。

使用 PythonLexer,您可以为每一行提取标记并添加您想要的任何 cmets。如果您不想只处理 while 循环,还想处理 for 循环、if 语句,这将派上用场...

【讨论】:

    【解决方案2】:

    pyparsing 有一个包含完整 (?) Python 语法分析器的示例文件。从长远来看,这可能是一个有趣的选择——尤其是当您的分析项目将获得更多功能时:

    【讨论】:

    【解决方案3】:

    执行此操作的最简单方法是简单地逐行扫描文件并在找到匹配的行时添加语句。

    以下代码可以满足您的要求,但它完全可靠:

    def add_info_on_loops(iterable):
        in_loop = False
        for line in iterable:
            if not in_loop:
                if line.startswith('for ') or line.startswith('while '):
                    in_loop = True
                    yield 'count = 0\n'
                    yield 'print "Entry of loop"\n'
                    yield line
                    yield '    print "Iteration Number:", count'
                    yield '    count += 1\n'
                else:
                    yield line
            else:
                if not line.startswith('    '):
                    in_loop = False
                    yield 'print "Exit of loop"\n'
                yield line
    

    用法:

    >>> code = StringIO("""[code Starts]
    ... .
    ... .
    ... .
    ... while [condition]:
    ...     [statements]
    ...     [statements]
    ...     [statements]
    ... 
    ... .
    ... .
    ... .
    ... [code ends]""")
    >>> print ''.join(add_info_on_loops(code))
    [code Starts]
    .
    .
    .
    count = 0
    print "Entry of loop"
    while [condition]:
        print "Iteration Number:", count    count += 1
        [statements]
        [statements]
        [statements]
    print "Exit of loop"
    
    .
    .
    .
    [code ends]
    

    代码的缺陷:

    1. 代码在顶层处理循环。无法识别像 if condition: for x in a: ... 这样的东西。这可以解决在检查是否有循环之前去除空白行(但您必须考虑不同级别的缩进等)
    2. 只要循环中有一行没有缩进,代码就会中断。例如,如果您用空行“拆分”代码并且 IDE 去除空白,就会发生这种情况。一个解决方案可能是等待一个非空白、非缩进的行而不是非缩进的行。
    3. 代码不处理用于缩进的制表符(很容易修复)
    4. 代码不处理单行循环(例如for x in a: print x)。在这种情况下,您将获得错误的输出。轻松修复检查:之后是否有内容。
    5. 如果要添加对嵌套循环的支持,使用单个 count 变量会很麻烦。您可能应该在某处有一个整数 id,并使用变量名称,例如 count_0count_1,每次找到新循环时,该 id 都会递增。
    6. 代码不处理带有括号且键盘上没有空格的表达式。例如for(a,b) in x: 未被检测为循环,而for (a,b) in x: 被检测到。这很容易解决。首先检查该行是否以forwhile 开头,并且下一个字符不能是字母、数字、下划线(实际上在python3中你也可以使用unicode字符,这变得更难测试,但可能) .
    7. 代码不处理以缩进循环行结尾的源代码。例如for x in a: indented_last_line_of_code()退出print不会被添加。(很容易修复在函数的for之外添加一个检查in_loop,看看我们是否有这种情况)。

    正如您所见,编写一段代码来满足您的要求并不是那么简单。 我相信你能做的最好的就是使用ast解析代码然后访问树并在正确的位置添加节点,然后重新访问代码并生成python源代码(通常节点有指示就行了在源代码中,它允许您复制粘贴完全相同的代码)。

    【讨论】:

      猜你喜欢
      • 2017-11-19
      • 2018-06-12
      • 1970-01-01
      • 1970-01-01
      • 2021-07-31
      • 1970-01-01
      • 1970-01-01
      • 2016-10-08
      • 1970-01-01
      相关资源
      最近更新 更多