История изменений
Исправление ados, (текущая версия) :
Спасибо всем за ответы. В результате снижение использования регулярок и, в особенности, перевод на множества дали заметное, но небольшое ускорение. Последнее значительно улучшило читаемость кода.
Но сильнее ускорил переход с difflib на rapidfuzz, благо последний получилось собрать на android. Получилось:
#!/usr/bin/env python
import sys, re, os
from pathlib import Path
from rapidfuzz import process as fuzz
from rapidfuzz import fuzz as fuzzmethod
def regexp_compile (r):
return re.compile(r, re.IGNORECASE)
def words_generator (buff):
length = len(buff)
start = 0
while start < length:
x = buff.find(b'\x00', start)
yield buff[start:x].decode('utf-8')
start = x + 9 # 1 byte for \0 + 4 bytes * 2
## 32 bit for word index and 32 bit for word length
class RegexAccumulator:
def __init__ (self, regexp):
self.collection = set()
self.regexp = regexp_compile(regexp)
def accumulate (self, words):
self.collection.update(s for s in words if self.regexp.fullmatch(s))
def result (self):
result = sorted(self.collection)
result.reverse()
return result
class UsualAccumulator:
def __init__ (self, word):
self.word = word
self.lword = word.lower()
self.wlen = len(word)
self.rset = set()
self.dm_set = set()
self.breg = regexp_compile(re.escape(word))
def accumulate (self, words):
self.rset.update(s for s in words if self.lword in s.lower())
m = map(lambda x: x[0],
fuzz.extract(self.word, words,
scorer=fuzzmethod.QRatio,
score_cutoff=70,
limit=400))
self.dm_set.update(m)
def result (self):
result = list()
self.dm_set.difference_update(self.rset)
set2 = set()
set2.update(s for s in self.rset if self.breg.match(s))
self.rset.difference_update(set2)
if self.word in set2:
result.append(word)
set2.discard(word)
result.extend(sorted(set2))
result.extend(sorted(self.rset))
result.extend(sorted(self.dm_set))
result.reverse()
return result
if __name__ == "__main__":
word = sys.argv[1]
if word == "-r" and len(sys.argv) > 2:
accumulator = RegexAccumulator(sys.argv[2])
else:
accumulator = UsualAccumulator(word)
files = Path(os.environ['STARDICT_DATA_DIR']).rglob("*.[iI][dD][xX]")
for name in files:
with open(name, 'rb') as f:
## My biggest .idx file ~ 11Mb so ...
buff = f.read()
accumulator.accumulate(list(words_generator(buff)))
for word in accumulator.result():
print(word)
На тесте перевод на множество сократил время работы с 4 минут до чуть более 3 минут, а rapidfuzz довёл время выполнения до ~ 35 сек.
Исходная версия ados, :
Спасибо всем за ответы. В результате снижение использования регулярок и, в особенности, перевод на множества дали заметный, но небольшое ускорение. Последнее значительно улучшило читаемость кода.
Но сильнее ускорил переход с difflib на rapidfuzz, благо последний получилось собрать на android. Получилось:
#!/usr/bin/env python
import sys, re, os
from pathlib import Path
from rapidfuzz import process as fuzz
from rapidfuzz import fuzz as fuzzmethod
def regexp_compile (r):
return re.compile(r, re.IGNORECASE)
def words_generator (buff):
length = len(buff)
start = 0
while start < length:
x = buff.find(b'\x00', start)
yield buff[start:x].decode('utf-8')
start = x + 9 # 1 byte for \0 + 4 bytes * 2
## 32 bit for word index and 32 bit for word length
class RegexAccumulator:
def __init__ (self, regexp):
self.collection = set()
self.regexp = regexp_compile(regexp)
def accumulate (self, words):
self.collection.update(s for s in words if self.regexp.fullmatch(s))
def result (self):
result = sorted(self.collection)
result.reverse()
return result
class UsualAccumulator:
def __init__ (self, word):
self.word = word
self.lword = word.lower()
self.wlen = len(word)
self.rset = set()
self.dm_set = set()
self.breg = regexp_compile(re.escape(word))
def accumulate (self, words):
self.rset.update(s for s in words if self.lword in s.lower())
m = map(lambda x: x[0],
fuzz.extract(self.word, words,
scorer=fuzzmethod.QRatio,
score_cutoff=70,
limit=400))
self.dm_set.update(m)
def result (self):
result = list()
self.dm_set.difference_update(self.rset)
set2 = set()
set2.update(s for s in self.rset if self.breg.match(s))
self.rset.difference_update(set2)
if self.word in set2:
result.append(word)
set2.discard(word)
result.extend(sorted(set2))
result.extend(sorted(self.rset))
result.extend(sorted(self.dm_set))
result.reverse()
return result
if __name__ == "__main__":
word = sys.argv[1]
if word == "-r" and len(sys.argv) > 2:
accumulator = RegexAccumulator(sys.argv[2])
else:
accumulator = UsualAccumulator(word)
files = Path(os.environ['STARDICT_DATA_DIR']).rglob("*.[iI][dD][xX]")
for name in files:
with open(name, 'rb') as f:
## My biggest .idx file ~ 11Mb so ...
buff = f.read()
accumulator.accumulate(list(words_generator(buff)))
for word in accumulator.result():
print(word)
На тесте перевод на множество сократил время работы с 4 минут до чуть более 3 минут, а rapidfuzz довёл время выполнения до ~ 35 сек.