Ada*_*dam 18 python regex pickle
我有一个包含300多个正则表达式的python控制台应用程序.每个版本都修复了正则表达式集.当用户运行应用程序时,整个正则表达式集将应用于从一次(非常短的工作)到数千次(长时间工作)的任何地方.
我想通过预先编译正则表达式,将编译的正则表达式pickle到文件,然后在运行应用程序时加载该文件来加快较短的作业.
python re模块是高效的,正则表达式编译开销对于长作业来说是完全可以接受的.然而,对于短期工作,它占整个运行时间的很大一部分.一些用户希望运行许多小作业以适应他们现有的工作流程.编译正则表达式大约需要80毫秒.除正则表达式编译外,短作业可能需要20ms-100ms.因此,对于短期工作,开销可以是100%或更多.这是在Windows和Linux下的Python27.
必须使用DOTALL标志应用正则表达式,因此需要在使用前进行编译.在这种情况下,大型编译缓存显然无济于事.正如一些人已经指出的那样,序列化编译的正则表达式的默认方法实际上并没有做太多.
re和sre模块将模式编译成一个小的自定义语言,具有自己的操作码和一些辅助数据结构(例如,用于表达式中使用的字符集).re.py中的pickle函数可以轻松实现.它是:
def _pickle(p):
return _compile, (p.pattern, p.flags)
copy_reg.pickle(_pattern_type, _pickle, _compile)
Run Code Online (Sandbox Code Playgroud)
我认为这个问题的一个很好的解决方案是更新re.py中_pickle的定义,它实际上是对已编译的模式对象进行了腌制.不幸的是,这超出了我的python技能.不过,我打赌,这里有人知道该怎么做.
我意识到我不是第一个提出这个问题的人 - 但也许你可以成为第一个对它做出准确而有用的回应的人!
非常感谢您的建议.
Ned*_*der 11
好吧,这不是很好,但它可能是你想要的.我查看了Python 2.6中的sre_compile.py模块,并将其删除了一半,将其切成两半,并使用这两个部分来挑选和解开编译的正则表达式:
import re, sre_compile, sre_parse, _sre
import cPickle as pickle
# the first half of sre_compile.compile
def raw_compile(p, flags=0):
# internal: convert pattern list to internal format
if sre_compile.isstring(p):
pattern = p
p = sre_parse.parse(p, flags)
else:
pattern = None
code = sre_compile._code(p, flags)
return p, code
# the second half of sre_compile.compile
def build_compiled(pattern, p, flags, code):
# print code
# XXX: <fl> get rid of this limitation!
if p.pattern.groups > 100:
raise AssertionError(
"sorry, but this version only supports 100 named groups"
)
# map in either direction
groupindex = p.pattern.groupdict
indexgroup = [None] * p.pattern.groups
for k, i in groupindex.items():
indexgroup[i] = k
return _sre.compile(
pattern, flags | p.pattern.flags, code,
p.pattern.groups-1,
groupindex, indexgroup
)
def pickle_regexes(regexes):
picklable = []
for r in regexes:
p, code = raw_compile(r, re.DOTALL)
picklable.append((r, p, code))
return pickle.dumps(picklable)
def unpickle_regexes(pkl):
regexes = []
for r, p, code in pickle.loads(pkl):
regexes.append(build_compiled(r, p, re.DOTALL, code))
return regexes
regexes = [
r"^$",
r"a*b+c*d+e*f+",
]
pkl = pickle_regexes(regexes)
print pkl
print unpickle_regexes(pkl)
Run Code Online (Sandbox Code Playgroud)
我真的不知道这是否有效,或者是否加快了速度.我知道它在我尝试时会打印一份正则表达式列表.它可能对2.6版本非常具体,我也不知道.
正如其他人所提到的,你可以简单地挑选编译的正则表达式.他们会腌制和去腌制得很好,并且可以使用.但是,它看起来并不像pickle实际上包含编译结果.我怀疑当你使用unpickling的结果时,你会再次产生编译开销.
>>> p.dumps(re.compile("a*b+c*"))
"cre\n_compile\np1\n(S'a*b+c*'\np2\nI0\ntRp3\n."
>>> p.dumps(re.compile("a*b+c*x+y*"))
"cre\n_compile\np1\n(S'a*b+c*x+y*'\np2\nI0\ntRp3\n."
Run Code Online (Sandbox Code Playgroud)
在这两个测试中,您可以看到两个泡菜之间的唯一区别在于字符串.显然编译的正则表达式不会腌制编译的位,只需要再次编译它所需的字符串.
但我总体上想知道你的应用程序:编译一个正则表达式是一个快速的操作,编译正则表达式的工作有多短暂?一种可能性是你正在编译所有300个正则表达式,然后只使用一个用于短期工作.在这种情况下,不要预先编译它们.re模块非常擅长使用已编译正则表达式的缓存副本,因此您通常不必自己编译它们,只需使用字符串形式.re模块将在编译的正则表达式的字典中查找字符串,因此自己抓取编译的表单只会节省字典查找.我可能完全偏离基础,对不起,如果是这样的话.
| 归档时间: |
|
| 查看次数: |
2314 次 |
| 最近记录: |