python3正则表达式替换_在Python 3中加速数百万的正则表达式替换

TLDR

如果您想要最快的解决方案,请使用此方法(使用set lookup)。对于类似于OP的数据集,它比接受的答案快约2000倍。

如果你坚持使用正则表达式进行查找,请使用这个基于trie的版本,它仍然比正则表达式联合快1000倍。

理论

如果你的句子不是巨大的字符串,那么处理每秒超过50的句子可能是可行的。

如果将所有被禁止的单词保存到一个集合中,检查该集合中是否包含另一个单词将非常快。

将逻辑打包成一个函数,将此函数作为参数,re.sub然后完成!

码import rewith open('/usr/share/dict/american-english') as wordbook:

banned_words = set(word.strip().lower() for word in wordbook)def delete_banned_words(matchobj):

word = matchobj.group(0)

if word.lower() in banned_words:

return ""

else:

return word

sentences = ["I'm eric. Welcome here!", "Another boring sentence.",

"GiraffeElephantBoat", "sfgsdg sdwerha aswertwe"] * 250000word_pattern = re.compile('\w+')for sentence in sentences:

sentence = word_pattern.sub(delete_banned_words, sentence)

转换后的句子是:' .  !

.

GiraffeElephantBoat

sfgsdg sdwerha aswertwe

注意:搜索不区分大小写(感谢lower())

替换一个单词""可能会留下两个空格(如代码中所示)

使用python3,\w+也匹配重音字符(例如"ångström")。

任何非单词字符(制表符,空格,换行符,标记......)都将保持不变。

性能

有一百万个句子,banned_words有近10万个单词,脚本运行不到7秒。

相比之下,Liteye的答案需要160秒才能完成1万个句子。

随着n是的话总amound和m明令禁止的单词的数量,OP的和Liteye的代码是O(n*m)。

相比之下,我的代码应该运行O(n+m)。考虑到句子比禁止的单词多得多,算法就变成了O(n)。

正则表达式联合测试

使用'\b(word1|word2|...|wordN)\b'模式进行正则表达式搜索的复杂性是多少?难道O(N)还是O(1)?

掌握正则表达式引擎的工作方式非常困难,所以让我们编写一个简单的测试。

此代码将10**i随机英语单词提取到列表中。它创建了相应的正则表达式联合,并使用不同的单词对其进行测试:一个显然不是一个词(它开头#)

一个是列表中的第一个单词

一个是列表中的最后一个单词

一个看起来像一个词但不是

import reimport timeitimport randomwith open('/usr/share/dict/american-english') as wordbook:

english_words = [word.strip().lower() for word in wordbook]

random.shuffle(english_words)print("First 10 words :")print(english_words[:10])test_words = [

("Surely not a word", "#surely_NöTäWORD_so_regex_engine_can_return_fast"),

("First word", english_words[0]),

("Last word", english_words[-1]),

("Almost a word", "couldbeaword")]def find(word):

def fun():

return union.match(word)

return funfor exp in range(1, 6):

print("\nUnion of %d words" % 10**exp)

union = re.compile(r"\b(%s)\b" % '|'.join(english_words[:10**exp]))

for description, test_word in test_words:

time = timeit.timeit(find(test_word), number=1000) * 1000

print("  %-17s : %.1fms" % (description, time))

它输出:First 10 words :["geritol's", "sunstroke's", 'fib', 'fergus', 'charms', 'canning', 'supervisor', 'fallaciously', "heritage's", 'pastime']Union of 10 words  Surely not a word : 0.7ms

First word        : 0.8ms

Last word         : 0.7ms

Almost a word     : 0.7msUnion of 100 words  Surely not a word : 0.7ms

First word        : 1.1ms

Last word         : 1.2ms

Almost a word     : 1.2msUnion of 1000 words  Surely not a word : 0.7ms

First word        : 0.8ms

Last word         : 9.6ms

Almost a word     : 10.1msUnion of 10000 words  Surely not a word : 1.4ms

First word        : 1.8ms

Last word         : 96.3ms

Almost a word     : 116.6msUnion of 100000 words  Surely not a word : 0.7ms

First word        : 0.8ms

Last word         : 1227.1ms

Almost a word     : 1404.1ms

所以看起来像搜索带有'\b(word1|word2|...|wordN)\b'模式的单个单词有:O(1) 最好的情况

O(n/2) 平均情况,这仍然是 O(n)

O(n) 最糟糕的情况

这些结果与简单的循环搜索一致。

正则表达式联合的一个更快的替代方法是从trie创建正则表达式模式。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值