每次导入包含大量静态正则表达式的 python 文件时,都会花费 CPU 周期将字符串编译到内存中的代表性状态机中。

a = re.compile("a.*b")
b = re.compile("c.*d")
...

问题:是否可以以预编译的方式将这些正则表达式存储在磁盘上的缓存中,以避免在每次导入时执行正则表达式编译?

Pickle 对象只是执行以下操作,无论如何都会导致编译发生:

>>> import pickle
>>> import re
>>> x = re.compile(".*")
>>> pickle.dumps(x)
"cre\n_compile\np0\n(S'.*'\np1\nI0\ntp2\nRp3\n."

re 对象是不可编组的:

>>> import marshal
>>> import re
>>> x = re.compile(".*")
>>> marshal.dumps(x)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: unmarshallable object
有帮助吗?

解决方案

是否可以以预编译的方式将这些正则表达式存储在磁盘上的缓存中,以避免在每次导入时执行正则表达式编译?

不容易。您必须编写一个挂钩到 C 的自定义序列化程序 sre Python 正则表达式引擎的实现。所需的时间和精力将远远超过任何性能优势。

首先,您是否真正分析过代码?我怀疑编译正则表达式是应用程序运行时的重要组成部分。请记住,它们仅在当前执行中第一次导入模块时进行编译 - 此后,模块及其属性将缓存在内存中。

如果您有一个程序基本上生成一次,编译一堆正则表达式,然后退出,您可以尝试重新设计它以在一次调用中执行多个测试。然后您可以重复使用正则表达式,如上所述。

最后,您可以将正则表达式编译成基于 C 的状态机,然后将它们与扩展模块链接。虽然这可能更难以维护,但它将完全从您的应用程序中消除正则表达式编译。

其他提示

请注意,每个模块在应用程序的生命周期中仅初始化一次,无论您导入多少次。因此,如果您在模块的全局范围内编译表达式(即不在函数中)你应该没问题。

首先,这是 python re 模块中的一个明显的限制。它限制了正则表达式的合理程度和大小。对于长时间运行的进程,该限制较大;对于命令行应用程序等短期进程,该限制较小。

几年前我确实看过它,可以挖掘出编译结果,pickle它,然后unpickle它并重用它。问题是它需要使用 sre.py 内部结构,因此可能无法在不同的 python 版本中工作。

我希望我的工具箱中有这样的功能。我还想知道是否有任何单独的模块可以替代。

搁置 模块似乎工作得很好:


import re
import shelve
a_pattern = "a.*b"
b_pattern = "c.*d"
a = re.compile(a_pattern)
b = re.compile(b_pattern)

x = shelve.open('re_cache')
x[a_pattern] = a
x[b_pattern] = b
x.close()

# ...
x = shelve.open('re_cache')
a = x[a_pattern]
b = x[b_pattern]
x.close()

然后,您可以创建一个漂亮的包装类,它自动为您处理缓存,以便它对用户变得透明......留给读者的练习。

打开 /usr/lib/python2.5/re.py 并查找“def _compile”。您会发现 re.py 的内部缓存机制。

可以将每个正则表达式(或正则表达式组)放入单独的文件中,然后使用 imp 模块动态导入所需的文件。我怀疑它的扩展性是否很好,但它可能正是您所需要的。

哼,

架子上不用pickle吗?

不管怎样,我同意前面的答案。由于模块仅处理一次,我怀疑编译正则表达式将成为您的应用程序瓶颈。Python re 模块速度非常快,因为它是用 C 编写的:-)

但好消息是 Python 拥有一个很好的社区,所以我相信您可以找到目前正在开发您所需要的东西的人。

我用谷歌搜索了 5 秒,发现: http://home.gna.org/oomadness/en/cerealizer/index.html.

不知道它是否会做到这一点,但如果没有,祝你研究好运:-)

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top