2015-04-15 6 views
1

У меня около 5000 файлов, и мне нужно найти слова в каждом из них из 10000 слов. В моем текущем коде используется (очень) длинное регулярное выражение, но это очень медленно.Каков наилучший способ поиска большого количества слов в большом количестве файлов?

wordlist = [...list of around 10000 english words...] 
filelist = [...list of around 5000 filenames...] 
wordlistre = re.compile('|'.join(wordlist), re.IGNORECASE) 
discovered = [] 

for x in filelist: 
    with open(x, 'r') as f: 
     found = wordlistre.findall(f.read()) 
    if found: 
     discovered = [x, found] 

Это проверяет файлы со скоростью около 5 файлов в секунду, что намного быстрее, чем делать это вручную, однако он по-прежнему очень медленно. Есть лучший способ сделать это?

+1

Рассмотрите возможность использования команд bash вместо Python, если вы используете Linux. – Raptor

+1

Использовать 'threads' или' multiprocessing' – vks

+0

@Raptor Я использую окна, но вполне возможно скопировать файлы в ящик linux. – Daffy

ответ

0

Если у вас есть доступ к grep в командной строке, вы можете попробовать следующее:

grep -i -f wordlist.txt -r DIRECTORY_OF_FILES 

Вам нужно создать файл wordlist.txt всех слов (одно слово в каждой строке).

Любых строк в любом из файлов, которые соответствуют любым из ваших слов будут напечатаны в STDOUT в следующем формате:

<path/to/file>:<matching line> 
+0

p.s. 'grep' только для UNIX. Используйте 'findstr' в системе на базе Windows: https://technet.microsoft.com/en-us/library/cc732459.aspx – Raptor

0

Без дополнительной информации о данных, пара мыслей использовать словари вместо списков и уменьшить данные, необходимые для поиска/сортировки. Также рекомендуется использовать re.split, если ваши разделители не так чисты, как показано ниже:

wordlist = 'this|is|it|what|is|it'.split('|') 
d_wordlist = {} 

for word in wordlist: 
    first_letter = word[0] 
    d_wordlist.setdefault(first_letter,set()).add(word) 

filelist = [...list of around 5000 filenames...] 
discovered = {} 

for x in filelist: 
    with open(x, 'r') as f: 
     for word in f.read(): 
      first_letter = word[0] 
      if word in d_wordlist[first_letter]: 
       discovered.get(x,set()).add(word) 

return discovered 
+0

Лучше сделать набор из списка слов и позволить python выполнять оптимизацию поиска. Btw. [file.read()] (https://docs.python.org/2/library/stdtypes.html#file.read) не возвращает список слов. – swenzel

0

Aho-Corasick algorithm был разработан именно для такого использования, и реализован как fgrep в Unix. С помощью POSIX для выполнения этой функции определяется команда grep -F.

Он отличается от обычного grep тем, что использует только фиксированные строки (не регулярные выражения) и оптимизирован для поиска большого количества строк.

Чтобы запустить его на большом количестве файлов, указать точные файлы в командной строке, или передать их через xargs:

xargs -a filelist.txt grep -F -f wordlist.txt 

Функция xargs является для заполнения командной строки с, как многие файлов, и запустите grep столько раз, сколько необходимо;

grep -F -f wordlist.txt (files 1 through 2,500 maybe) 
grep -F -f wordlist.txt (files 2,501 through 5,000) 

Точное количество файлов на вызов зависит от длины отдельных имен файлов, и размера ARG_MAX постоянная в вашей системе.

+0

Нетрудно найти порты 'grep' для Windows; но они могут отличаться по качеству. Я бы предложил искать GNU 'grep' для Windows. Первый хит Google для меня - http://gnuwin32.sourceforge.net/packages/grep.htm – tripleee

+0

Существуют модули Python, которые также реализуют этот алгоритм, но я не знаю, какой из них рекомендовать. https://pypi.python.org/pypi/ahocorasick/0.9 - это лучший хит Google для меня, но он имеет более низкий номер версии и выглядит менее отполированным, чем https://pypi.python.org/pypi/pyahocorasick/1.0.0 – tripleee