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

TLDR

如果您想要最快的基于正则表达式的解决方案,请使用此方法。 对于类似于OP的数据集,它比接受的答案快大约1000倍。

如果您不关心正则表达式,请使用此基于集合的版本,这比正则表达式联合快2000倍。

使用Trie优化正则表达式

由于正则表达式引擎在优化模式方面做得不是很好,因此简单的正则表达式联合方法会因许多被禁止的单词而变得缓慢。

可以使用所有被禁止的单词创建Trie并编写相应的正则表达式。 由此产生的trie或regex并不是人类可读的,但它们确实允许非常快速的查找和匹配。

['foobar', 'foobah', 'fooxar', 'foozap', 'fooza']

该列表转换为trie:

{

'f': {

'o': {

'o': {

'x': {

'a': {

'r': {

'': 1

}

}

},

'b': {

'a': {

'r': {

'': 1

},

'h': {

'': 1

}

}

},

'z': {

'a': {

'': 1,

'p': {

'': 1

}

}

}

}

}

}

}

然后到这个正则表达式模式:

r"\bfoo(?:ba[hr]|xar|zap?)\b"

最大的优点是,为了测试twopi是否匹配,正则表达式引擎只需要比较第一个字符(它不匹配),而不是尝试5个字。 这是一个5个单词的预处理矫枉过正,但它显示了数千个单词的有希望的结果。

请注意,使用了twopi非捕获组,因为:

twopi将匹配foobar或baz,但不是twopi

twopi会将不需要的信息保存到捕获组。

这是一个稍微修改过的要点,我们可以将其用作twopi库:

import re

class Trie():

"""Regex::Trie in Python. Creates a Trie out of a list of words. The trie can be exported to a Regex pattern.

The corresponding Regex should match much faster than a simple Regex union."""

def __init__(self):

self.data = {}

def add(self, word):

ref = self.data

for char in word:

ref[char] = char in ref and ref[char] or {}

ref = ref[char]

ref[''] = 1

def dump(self):

return self.data

def quote(self, char):

return re.escape(char)

def _pattern(self, pData):

data = pData

if "" in data and len(data.keys()) == 1:

return None

alt = []

cc = []

q = 0

for char in sorted(data.keys()):

if isinstance(data[char], dict):

try:

recurse = self._pattern(data[char])

alt.append(self.quote(char) + recurse)

except:

cc.append(self.quote(char))

else:

q = 1

cconly = not len(alt) > 0

if len(cc) > 0:

if len(cc) == 1:

alt.append(cc[0])

else:

alt.append('[' + ''.join(cc) + ']')

if len(alt) == 1:

result = alt[0]

else:

result = "(?:" + "|".join(alt) + ")"

if q:

if cconly:

result += "?"

else:

result = "(?:%s)?" % result

return result

def pattern(self):

return self._pattern(self.dump())

测试

这是一个小测试(与此相同):

# Encoding: utf-8

import re

import timeit

import random

from trie import Trie

with open('/usr/share/dict/american-english') as wordbook:

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

random.shuffle(banned_words)

test_words = [

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

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

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

("Almost a word", "couldbeaword")

]

def trie_regex_from_words(words):

trie = Trie()

for word in words:

trie.add(word)

return re.compile(r"\b" + trie.pattern() + r"\b", re.IGNORECASE)

def find(word):

def fun():

return union.match(word)

return fun

for exp in range(1, 6):

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

union = trie_regex_from_words(banned_words[:10**exp])

for description, test_word in test_words:

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

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

它输出:

TrieRegex of 10 words

Surely not a word : 0.3ms

First word : 0.4ms

Last word : 0.5ms

Almost a word : 0.5ms

TrieRegex of 100 words

Surely not a word : 0.3ms

First word : 0.5ms

Last word : 0.9ms

Almost a word : 0.6ms

TrieRegex of 1000 words

Surely not a word : 0.3ms

First word : 0.7ms

Last word : 0.9ms

Almost a word : 1.1ms

TrieRegex of 10000 words

Surely not a word : 0.1ms

First word : 1.0ms

Last word : 1.2ms

Almost a word : 1.2ms

TrieRegex of 100000 words

Surely not a word : 0.3ms

First word : 1.2ms

Last word : 0.9ms

Almost a word : 1.6ms

有关信息,正则表达式开头如下:

????(:一个(:(:\' S |一个(:\' S |陈| liyah(:????\' S)| R(:dvark(? :(?:\' S | S))| ON))| b(:\' S | A(:??????C(:我们(:(:\&#39 ; S | ES))| [IK])|英尺|孤(:???(?:?\' S | S))| NDON(:( ?:编| ING |换货(:\ ?????' S)| S))| S(:E(:( ?:换货(:\' S)| [DS))| H(:(???? ?:E [DS] |荷兰国际集团))|荷兰国际集团)| T(:E(:( ?:换货(:\' S)| [DS]))|荷兰国际集团| toir(?????? :(?:\' S | S))))| b'(:如(:ID)| E(:SS(:(:??????\' S | ES) ?)| Y(?:?(:\' S | S)))| OT?(?:?(:\' S | T(?:\' S)?| ?S))| reviat(:?????E [DS] | I(:纳克|上(:(:\' S | S))))| Y(?:?\&#39 ; S)| \é?(?:?(:\' S | S)))| d(:?????ICAT(:E [DS] | I(:纳克|上(?: (?:\' S | S))))| OM(:????恩(:(:\' S | S))|伊纳勒)| U(?:CT(? :( ?: ED | I(:纳克|上(:(:????\' S | S)))|或(?:?(:\' S | S))? ?| S))| L(:\' s)))| E(:???(:\' S |上午| L(?:?(:\' S | ARD |子(?:\' s)))| R(?:???DEEN(:\' S)| nathy(?:??\' S)| RA (:???NT |和灰(:(:\' S | S))?))| T(:( ?:吨(:?????E(:R(:(:\& ????#39; S | S))| d)| ING |或(:(:\' S | S)))| S))| yance(:???\' S ?)| d))| HOR(:( ?: R(:E(为:n(:CE(:??????\' S)| T)| d)|荷兰国际集团)| S ?))| I(:????d(:E [DS] |荷兰国际集团|一月(:\' S))|盖尔| L(:???烯|它(:IES | Y(:\' S'))))| J〜(:ECT(:LY)| UR(:通货膨胀(:(:??????\' S | S))? | E [DS] |荷兰国际集团))| L(:一个(:略去(:(:????\' S | S))|???ZE)| E(:( ?: ST | ????R))| OOM | ution(:(:\' S | S))| Y)|米\' S | N(:????E(:GAT(:电子?[DS] | I(:?纳克|上(:\' S)?))| R(?:\' S))| ormal(:( ?:它(???? :IES | Y(?:\' S))| LY)))| O(:ARD |德(:(:??????\' S | S))|李( ?:SH |)|和灰(:(:\' S | IST(:(:( ?: E [DS]荷兰国际集团?)???(?:?\' S | S)) ?)))|米娜(:BL [EY] | T(:E [DS] | I(:纳克|上(:(:??????\' S | S))?)? ))| R(:????igin(:人(:(:\' S | S))| E'?(?:?(:\' S | S)))| ?吨(:( ?: ED | I(:纳克|上(:(:???\' S | IST(:(:???\' S | S))| S) ?)|阳离子)| S)))| U(:ND(:( ?:编| ING | S))| T)| VE(:(:??????\' S |板)))| R(:一个(:cadabra(:?????\' S)| d(:E [DS] |荷兰国际集团)|火腿(:???\' S) ?| M(?:?(:\' S | S))| SI(:????上(:(?:\' S | S))| VE(:(? :\' S | LY |岬(?:\' S)| S))))|东|腾讯科技讯(:?????E(:( ?:包换(:( ?: \' S | S))| [DS]))| ING |换货(:????(:\' S | S)))| O(:广告| GAT(???? ?:E [DS] | I(:???纳克|上(:(:\' S | S))?)))| UPT(:( ?: E(:?ST | r)的| LY |岬(?:\' S))))| S(:???ALOM | C(:ESS(:(:???\' S | E [DS] | ING ????))| ISSA(:(:\' S | [ES]))| OND(:( ?:编|在? ????克| S)))| EN(:CE(:(?:\' S | S))| T(:( ?: E(:E(:(:\???? ' S | ISM(?:\' S)| S))| d)| ING | LY | S)))| INTH(:?????(:\' S | E(?:\' S)))| O(:L(:UT(:E(:(:???????\' S | LY | ST))? | I(?:?上(:\' S)| SM(?:\' S)?))| v(?:E [DS] |荷兰国际集团))| R(α? :b(:( ?: E(为:n(:CY(:\' S)| T(:??????(?:?\' S | S)))| d )| ING | S))|?PTI ...

它真的难以理解,但是对于100000个被禁词的列表,这个Trie正则表达式比简单的正则表达式联合快1000倍!

这是一个完整的trie图,用trie-python-graphviz和graphviz twopi导出:

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值