TLDR
En hızlı çözümü istiyorsanız bu yöntemi (set aramalı) kullanın. OP'lere benzer bir veri kümesi için, kabul edilen cevaptan yaklaşık 2000 kat daha hızlıdır.
Arama için bir normal ifade kullanmakta ısrar ediyorsanız , hala bir normal ifade birleşiminden 1000 kat daha hızlı olan bu üçlü tabanlı sürümü kullanın .
teori
Cümleleriniz çok büyük dizeler değilse, saniyede 50'den fazlasını işlemek muhtemelen mümkündür.
Tüm yasaklanmış kelimeleri bir sete kaydederseniz, o sette başka bir kelimenin bulunup bulunmadığını kontrol etmek çok hızlı olacaktır.
Mantığı bir işleve paketleyin, bu işlevi bağımsız değişken olarak verin re.sub
ve bitirdiniz!
kod
import re
with 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"] * 250000
word_pattern = re.compile('\w+')
for sentence in sentences:
sentence = word_pattern.sub(delete_banned_words, sentence)
Dönüştürülen cümleler:
' . !
.
GiraffeElephantBoat
sfgsdg sdwerha aswertwe
Bunu not et:
- arama büyük / küçük harfe duyarlı değildir (sayesinde
lower()
)
- bir kelimeyi değiştirmek
""
iki boşluk bırakabilir (kodunuzda olduğu gibi)
- Python3 ile
\w+
ayrıca aksanlı karakterlerle eşleşir (örneğin "ångström"
).
- Sözcük olmayan herhangi bir karakter (sekme, boşluk, satırsonu, işaretler, ...) dokunulmadan kalacaktır.
Verim
Bir milyon cümle var, banned_words
neredeyse 100000 kelime var ve senaryo 7 saniyeden daha kısa sürede çalışıyor.
Buna karşılık, Liteye'nin cevabı 10 bin cümle için 160'lara ihtiyaç duyuyordu.
İle n
kelimelerin toplam yıkama çözeltisi ve varlık m
yasaklı kelimelerin miktarı, OP adlı ve Liteye kodu vardır O(n*m)
.
Buna karşılık, kodum çalışmalı O(n+m)
. Yasaklı sözcüklerden çok daha fazla cümle olduğu düşünüldüğünde algoritma olur O(n)
.
Normal ifade birleşim testi
Bir '\b(word1|word2|...|wordN)\b'
kalıpla normal ifade aramasının karmaşıklığı nedir ? Öyle mi O(N)
yoksa O(1)
?
Normal ifade motorunun çalışma şeklini kavramak oldukça zor, bu yüzden basit bir test yazalım.
Bu kod, 10**i
rastgele İngilizce kelimeleri bir listeye çıkarır . Karşılık gelen normal ifade birleşimini oluşturur ve farklı kelimelerle test eder:
- açıkça bir kelime değil (ile başlar
#
)
- listedeki ilk kelime
- listedeki son kelime
- bir kelime gibi görünüyor ama değil
import re
import timeit
import random
with 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 fun
for 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))
Çıktıları:
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.7ms
Union of 100 words
Surely not a word : 0.7ms
First word : 1.1ms
Last word : 1.2ms
Almost a word : 1.2ms
Union of 1000 words
Surely not a word : 0.7ms
First word : 0.8ms
Last word : 9.6ms
Almost a word : 10.1ms
Union of 10000 words
Surely not a word : 1.4ms
First word : 1.8ms
Last word : 96.3ms
Almost a word : 116.6ms
Union of 100000 words
Surely not a word : 0.7ms
First word : 0.8ms
Last word : 1227.1ms
Almost a word : 1404.1ms
Öyleyse, bir '\b(word1|word2|...|wordN)\b'
kalıba sahip tek bir kelime için yapılan arama şuna sahip gibi görünüyor :
O(1)
en iyi senaryo
O(n/2)
ortalama durum, ki hala O(n)
O(n)
En kötü durumda
Bu sonuçlar, basit bir döngü aramasıyla tutarlıdır.
Bir normal ifade birleşimine çok daha hızlı bir alternatif, bir üçlüden normal ifade kalıbı oluşturmaktır .