TLDR
यदि आप सबसे तेज़ रेगेक्स-आधारित समाधान चाहते हैं तो इस विधि का उपयोग करें। ओपी के समान एक डेटासेट के लिए, यह स्वीकृत उत्तर की तुलना में लगभग 1000 गुना तेज है।
यदि आप रेगेक्स के बारे में परवाह नहीं करते हैं, तो इस सेट-आधारित संस्करण का उपयोग करें , जो रेगेक्स यूनियन की तुलना में 2000 गुना तेज है।
तीनों के साथ अनुकूलित रेगेक्स
एक सरल रेगेक्स यूनियन दृष्टिकोण कई प्रतिबंधित शब्दों के साथ धीमा हो जाता है, क्योंकि रेगेक्स इंजन पैटर्न के अनुकूलन का बहुत अच्छा काम नहीं करता है ।
सभी प्रतिबंधित शब्दों के साथ एक ट्राय बनाना और संबंधित रेगेक्स लिखना संभव है । परिणामी trie या regex वास्तव में मानव-पठनीय नहीं हैं, लेकिन वे बहुत तेज़ी से देखने और मिलान करने की अनुमति देते हैं।
उदाहरण
['foobar', 'foobah', 'fooxar', 'foozap', 'fooza']
सूची को तिकड़ी में बदल दिया गया है:
{
'f': {
'o': {
'o': {
'x': {
'a': {
'r': {
'': 1
}
}
},
'b': {
'a': {
'r': {
'': 1
},
'h': {
'': 1
}
}
},
'z': {
'a': {
'': 1,
'p': {
'': 1
}
}
}
}
}
}
}
और फिर इस regex पैटर्न के लिए:
r"\bfoo(?:ba[hr]|xar|zap?)\b"
बहुत बड़ा फायदा यह है कि यदि zoo
मैच होता है तो परीक्षण करने के लिए , रेगेक्स इंजन को केवल 5 शब्दों की कोशिश करने के बजाय पहले चरित्र (यह मेल नहीं खाता) की तुलना करने की आवश्यकता है । यह 5 शब्दों के लिए एक प्रीप्रोसेस ओवरकिल है, लेकिन यह कई हजार शब्दों के लिए आशाजनक परिणाम दिखाता है।
ध्यान दें कि (?:)
गैर-कैप्चरिंग समूहों का उपयोग किया जाता है क्योंकि:
कोड
यहाँ थोड़ा संशोधित जिप है , जिसे हम trie.py
लाइब्रेरी के रूप में उपयोग कर सकते हैं :
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
जानकारी के लिए, रेगेक्स इस तरह शुरू होता है:
(: एक (: (: \ की | एक (: \ '??? रों | chen | Liyah (: \ के) | आर (? Dvark (: (? \ की | रों )) | पर)) | ख? (: \ की | एक (? ग (: हमें (: (: \?? 's | ते)) | [इक]) | फीट | अकेला (? : (: \ की | s)?) | ndon (? :( ?: एड | ing | जाहिर (: \ के) |?? s)) | s (: ई (? :( ?:? जाहिर: | [डी एस])) | ज (? :( ?: ई [डी एस] | ing)) | ing) | टी ((\ की?):????? ई (? :( ?: जाहिर ( ?: \ के) | [डी एस])) | ing | Toir (? (: \? 's | s)))) | ख (: के रूप में (?? आईडी) | ई (? : एस एस (: (? \ की | ते)) |? y (: (: \? '|) | OT (रों s)): (?? \ की | टी (: \ 'रों) | s)) | reviat? (: ई [डी एस] | मैं (? एनजी | पर (: (: \?' s | s)))) | y (? \ ' ? रों) | \ é (: (? \ की | s)?)) | घ (: ICAT (: ई [डी एस] | मैं (?? एनजी | पर (?? (: \ की | s)))) | ओम (: एन (: (: \?? 's | s)) | inal) | यू (?? सीटी (? :( ?: एड | मैं (?: एनजी | पर (: (: \? 's | s))) | या? (: (? \ की | s)???) | s)) | एल (: \ की)) ) | ई (: (? \ की | बजे | एल (: (? \ की | अर्द | बेटा (?? \ के))) | आर (? दीन (: \ 'रों) | Nathy? (: \ के) | ra (?? NT | tion (: (: \ की | s))?)) | टी (? :( ?: टी (?: ई (: आर (: (: \? 's | s)) | घ?) | ing | या (? (: \'रों | s))) | s)) | yance (? \ के) | घ)) | होर (? :( ?: आर (???? ई (: n (: ce (?? : \ के) | टी) | घ) | ing) | s)) | मैं (?? घ (: ई [डी एस] | ing | जनवरी (?? \ '? रों)) | गेल | एल (: ene | यह (? एँ | y (: \ के))?) | j | उर ((: ect (ly?):??? समझना (: (: \?) ' रों | s)) | ई [डी एस] | ing)) | एल (??? एक (: ेश्य (: (??? \ की | s)) | Ze) | ई (:(? : सेंट | र)) | oom | संविधान (? (??? \ '? रों | s)) | वाई) | मीटर \ की | n (: ई (: Gat (: ई [डी एस] ? | मैं (: एनजी | पर (: \ की)?) | आर (?: \?) के)) | ormal (? :( ?: यह (? एँ | y (? \ ' रों)) | ly))) | ओ (?? अर्द | डे (: (??? \ की | s)) | ली (: श (? :( ?: ई [डी एस] | आईएनजी )) | tion? (? (: \ की | IST (: (: \? 's | s))))) | मीना (?? बीएल [ey] | टी (: ई [ डी एस] | मैं? (: एनजी | पर (?? (: \ की | s))?))) | आर (??? igin (: अल (: (: \ की | s) ) | ई? (? (: \ की | s))) | टी (? :( ?: एड | मैं (? एनजी | पर (: (? \ की | IST (?: ) |)) एस | ve) | s))) | यू (|: (\ की है?):????? nd (? :( ?: एड | ing | s)) | टी) | ve (: (? \ की | बोर्ड))) | आर (?? एक (: Cadabra (: \? 'रों) | घ (?? ई [डी एस] | ing) | हैम (? : \ '? रों) | मीटर (: (? \ की | s)?) | si (: पर (: (?? \ की | s)) |? ve (? :( ?:?\ की | ly | सत्ता (: \? '| S)))) | पूर्व | IDG (रों)?? ई (? :( ?: जाहिर (: (?? \ की | s)) ? | [डी एस])) | ing | जाहिर (?? (: \ की | s))) | ओ (? विज्ञापन | Gat (: ई [डी एस] | मैं (?? एनजी | पर (: (: \??? 's | s))))) | upt (? :( ?: ई (??? सेंट | r) | ly | सत्ता (: \' रों)))) | रों (? आलम | ग (: ईएसएस (: (: \ की | ई [डी एस] | ing)) | Issa (? (? \ '?? रों | [es])) | दूसरी)) | एन (? :( ?: एड | | ing है?)? (? ce (: (? \ की | s)??) | टी (? :( ?: ई (: ई ( ?: (: \ की | वाद (: \? 'रों) | है?)) | घ) | ing | ly | s))) | inth (? (? \ की | ई ( ?: \ के))) | ओ? (?? एल (: ut (: ई (: (: \? 's | ly | सेंट)?) | मैं (? पर (?: \ '? रों) | एसएम (: \'? रों))) | v (: ई [डी एस] | ing)) | आर (?? ख (? :( ?: ई (: n (?? : cy (: \? '| टी रों)? (: (? \ की | s))?) | घ) | ing | s)) | PTI ...रों | [es])) | दूसरी (? :( ?: एड | ing | s))) | एन (??? ce (: (?? \ की | s)) | टी (?: (: ई (: ई (: (??? \ '? रों | वाद (: \'? रों) | s)) | घ) | ing | ly | s))) | inth (?: (: \ की | ई (: \? 'रों)?)) | ओ (? एल (: ut (: ई (: (: \ की | ly | सेंट))????? | मैं (: पर (: \ के) | एसएम (? \ '?? रों))?) | v (: ई [डी एस] | ing)) | आर (?? ख (:( ?: ई (: n (: cy (: \ के) | टी (: (? \ '??? रों | s))) | घ) |? ing | s)) | PTI .. ।रों | [es])) | दूसरी (? :( ?: एड | ing | s))) | एन (??? ce (: (?? \ की | s)) | टी (?: (: ई (: ई (: (??? \ '? रों | वाद (: \'? रों) | s)) | घ) | ing | ly | s))) | inth (?: (: \ की | ई (: \? 'रों)?)) | ओ (? एल (: ut (: ई (: (: \ की | ly | सेंट))????? | मैं (: पर (: \ के) | एसएम (? \ '?? रों))?) | v (: ई [डी एस] | ing)) | आर (?? ख (:( ?: ई (: n (: cy (: \ के) | टी (: (? \ '??? रों | s))) | घ) |? ing | s)) | PTI .. ।
यह वास्तव में अपठनीय है, लेकिन 100000 प्रतिबंधित शब्दों की सूची के लिए, यह ट्राइ रेगेक्स एक साधारण रेगेक्स यूनियन की तुलना में 1000 गुना तेज है!
यहाँ पूरी तिकड़ी का आरेख है, जिसे त्रि-पायथन-ग्राफविज़ और ग्राफविज़ के साथ निर्यात किया गया है twopi
: