20

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

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

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

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

>>> 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
4

7 回答 7

13

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

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

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

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

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

于 2008-09-15T18:29:51.187 回答
3

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

于 2008-09-15T18:16:24.277 回答
2

首先,这是 python re 模块中的一个明显限制。它会限制正则表达式的合理程度和大小。长期运行的进程限制更大,而命令行应用程序等短期进程的限制更小。

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

我想在我的工具箱中有这种功能。我还想知道,是否可以使用任何单独的模块。

于 2008-12-28T13:02:56.863 回答
0

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


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()

然后,您可以创建一个很好的包装类,自动为您处理缓存,使其对用户透明......留给读者的练习。

于 2008-09-15T19:14:24.730 回答
0

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

于 2008-09-15T20:53:14.900 回答
-1

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

于 2008-09-15T18:45:37.717 回答
-1

哼,

搁置不用泡菜吗?

无论如何,我同意以前的回答者。由于一个模块只处理一次,我怀疑编译正则表达式将成为您的应用程序瓶颈。而且 Python re 模块速度很快,因为它是用 C 编码的 :-)

但好消息是 Python 有一个不错的社区,所以我相信你可以找到目前正在破解你需要的东西的人。

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

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

于 2008-09-15T20:34:12.480 回答