从字符串中提取带括号的Python表达式

1 投票
4 回答
1243 浏览
提问于 2025-04-11 17:31

我一直在想,写一些Python代码来查找字符串中形如${expr}的子串的索引会有多难。比如,expr可以是一个Python表达式或者类似的东西。有了这样的东西,我们可以想象接下来用compile()来检查表达式的语法,用eval()在特定的环境中计算它的值,甚至可能把结果替换回原来的字符串中。人们肯定经常做类似的事情。

我可以想象用一个第三方的解析器生成器来解决这个问题,或者手动编写某种状态机,或者说服Python自己的解析器来完成这个重活。也许有某个第三方的模板库可以做到这一点。也许限制expr的语法会在简单性、执行时间或减少外部依赖方面是个值得的妥协——比如,也许我只需要匹配任何有平衡大括号的expr

你觉得怎么样?

更新:

非常感谢你们到目前为止的回复!回顾我昨天写的内容,我不太确定我是否清楚地表达了我的问题。模板替换确实是个有趣的问题,可能对很多人来说比我所关心的表达式提取子问题更有用,但我提到它只是作为一个简单的例子,说明我问题的答案在现实生活中可能会有用。其他一些潜在的应用可能包括将提取的表达式传递给语法高亮工具;将结果传递给真正的Python解析器,查看或修改解析树;或者利用提取的表达式序列构建一个更大的Python程序,也许还结合一些周围文本的信息。

我提到的${expr}语法也是作为一个例子,实际上我在想我是否应该用$(expr)作为例子,因为这样可以更容易地看出明显方法的潜在缺陷,比如re.finditer(r'$\{([^}]+)\}', s)。Python表达式可以(而且通常会)包含)(或}字符。处理这些情况可能会比它值得的麻烦多,但我还没有完全确定这一点。请随时尝试说服我!

在发布这个问题之前,我花了不少时间研究Python模板引擎,希望能找到一种能够提供我所询问的低级功能的工具——也就是说,能够在各种上下文中找到表达式并告诉我它们的位置,而不是仅限于使用单一硬编码语法找到嵌入的表达式,总是计算它们,并且总是将结果替换回原始字符串中。我还没有找到任何一个能解决我问题的方法,但我非常感谢你们提供的更多建议(真不敢相信我错过了维基上的那个精彩列表!)。这些东西的API文档通常比较高层次,我对它们的内部工作不太熟悉,所以我肯定需要帮助来查看这些内容,并弄清楚如何让它们做到这一点。

感谢你的耐心!

4 个回答

1

如果你想处理一些复杂的表达式,比如 {'{spam': 42}["spam}"],那么你就不能不使用一个完整的解析器。

2

我觉得你问的是如何把Python代码插入到文本文件中并进行评估。其实已经有好几个模块可以实现这个功能。你可以去Python.org的模板维基页面查看详细的列表。

通过谷歌搜索,我还找到了一些你可能感兴趣的其他模块:

如果你真的想自己写这个功能,不管出于什么原因,你也可以看看这个Python食谱中的解决方案又一个Python模板工具(YAPTU)

“模板化”(就是把输入文件复制到输出文件,同时动态插入Python表达式和语句)是一个常见的需求,而YAPTU是一个小而完整的Python模块,可以满足这个需求;表达式和语句是通过用户自定义的正则表达式来识别的。

编辑:为了好玩,我写了一个非常简单的代码示例。我知道它可能有bug,但至少能说明这个概念的简化版本:

#!/usr/bin/env python

import sys
import re

FILE = sys.argv[1]

handle = open(FILE)
fcontent = handle.read()
handle.close()

for myexpr in re.finditer(r'\${([^}]+)}', fcontent, re.M|re.S):
    text = myexpr.group(1)
    try:
        exec text
    except SyntaxError:
        print "ERROR: unable to compile expression '%s'" % (text)

测试以下文本:

This is some random text, with embedded python like 
${print "foo"} and some bogus python like

${any:thing}.

And a multiline statement, just for kicks: 

${
def multiline_stmt(foo):
  print foo

multiline_stmt("ahem")
}

More text here.

输出:

[user@host]$ ./exec_embedded_python.py test.txt
foo
ERROR: unable to compile expression 'any:thing'
ahem
1

我觉得你最好的办法是先找到所有大括号里的内容,然后再用Python来检查这些内容是否有效。这个时候可以用到compiler这个工具,它会很有帮助。

撰写回答