Поиск слов из списка в большом файле (Python)

Здравствуйте!

Возник вопрос: можно ли при помощи Python в большом файле на 2 миллиона строк (400 мегабайт) найти из списка на 10 тысяч строк все совпадения слов и вывести их на экран?

Мне нужно, чтобы в результате отображалось только то, какие слова из списка используются в файле. Мне достаточно лишь знать, что у слова есть хотя бы одно вхождение.

Файл на 2 миллиона строк при этом не является списком, а представляет из себя кашу подобного вида, где в случайном месте текста находятся искомые слова:

fR яя яя n яя < яя Ђ? Ђ? Ђ? яяяя яяютS яяa51_blastdoorL €Q яя яя lQ яя xB яя/ r H яя я яMMQя я93)яsKJяttzяeekя5-)яeejя я я>==яяEEIя я,&яяppvяllrя›Сїяhhmя я яя{ЏЊяяJJNяOOSя я001яKKOяeekя+%"я яяяєНїя яяќІ¬я яяusjяЏµ©яztgяяяGGJяYY^я,*+я224яWW[яZZ_я%%'яoouя=83я яя¶ГЇя2/1я++-яeekяя335яB=>яяMMQя я

Пример списка слов, которые я ищу в файле:

247sign1
247sign1_64
247sign2
711doors1
711shop1
747_cage
747_crate
747_freight1
a51_blastdoor
a51_boffstuff1

Для этих целей я имею следующий код:

f = open('all.txt', 'r', encoding='utf-8')
lines1 = set(f.read().split())
f.close()
f = open('alltext.txt', 'r', encoding='utf-8')
lines2 = set(f.read().split())
f.close()

print(lines1.intersection(lines2))

Я запускаю код, и по итогу он выдаёт мне всего 300 совпадений, которых на самом деле в этом файле должно быть примерно 10 тысяч. Я так понимаю, что имею дело с некоторыми ограничениями Python, который не может обработать такой большой объём данных. Прав ли я, и можно ли это как-то обойти, или же с моим кодом что-то не так? Или, может быть, для моих целей нужны какие-то другие инструменты и программы?

Заранее спасибо за ответ.


Ответы (4 шт):

Автор решения: CrazyElf

Пример использования регулярок:

import re

text = ''' fR яя яя  n яя < яя Ђ? Ђ? Ђ? яяяя яяютS яяa51_blastdoorL €Q яя яя  lQ яя xB яя/ r H яя я яMMQя я93)яsKJяttzяeekя5-)яeejя я я>==яяEEIя я,&яяppvяllrя›Сїяhhmя я яя{ЏЊяяJJNяOOSя я001яKKOяeekя+%"я яяяєНїя яяќІ¬я яяusjяЏµ©яztgяяяGGJяYY^я,*+я224яWW[яZZ_я%%'яoouя=83я яя¶ГЇя2/1я++-яeekяя335яB=>яяMMQя я'''
print(re.findall('[0-9a-z_]{5,}', text))

Вывод:

['a51_blastdoor']

Здесь отбираются "слова" минимум из 5 символов: латинских букв нижнего регистра, либо цифр, либо подчёркивания.

Но вообще тут нет гарантии, что к словам не прилепится что-то лишнее, в данном случае чуть не прилепилась большая буква L в конце, поэтому я большие буквы брать не стал. Лучше всё-таки выяснить, какой на самом деле формат этого файла, это явно двоичный формат, в котором данные вперемешку лежат текстовые и не текстовые.

→ Ссылка
Автор решения: Imas
import re

def search_keywords(filename, keywords):
  """
  Выполняет поиск ключевых слов в файле с помощью регулярных выражений.

  Аргументы:
    Имя файла: Путь к файлу для поиска.
    Ключевые слова: Список ключевых слов для поиска.

  Возвращается:
    Список кортежей, где каждый кортеж содержит ключевое слово и номер строки, в которой он был найден.
  """
  results = []
  with open(filename, 'r') as file:
    for line_number, line in enumerate(file, 1):
      for keyword in keywords:
        if re.search(keyword, line):
          results.append((keyword, line_number))
  return results

keywords_to_search = ['function', 'class', 'import']
file_to_search = 'your_file.py'
found_keywords = search_keywords(file_to_search, keywords_to_search)
print(f'Найденные ключевые слова в {file_to_search}:')
for keyword, line_number in found_keywords:
  print(f'- {keyword} найден на линии {line_number}')
→ Ссылка
Автор решения: MBo

Алгоритм Ахо-Корасик позволяет задать набор паттернов для поиска, и пройти по строкам, находя совпадения со всеми паттернами сразу (ещё один алгоритм с подобными свойствами - Commentz-Walter).

Библиотеки для Python c реализацией этого алгоритма есть, вот первое из поиска

Если у вас есть проблемы с интерпретацией бинарного файла как текстового (данные "портятся"), то ничего не мешает применить тот же алгоритм к файлу как набору байтов (вот какая-то простая реализация, в которой можно поменять строки на списки или массивы байтов)

→ Ссылка
Автор решения: vadim vaduxa
find_words = {'247sign1', '247sign1_64', '247sign2', '711doors1', '711shop1', '747_cage', '747_crate', 'a', 'continue', 'a51_boffstuff1', }
with open('alltext.txt', encoding='utf-8') as f:
    while find_words:  # выполнять пока есть слова для поиска
        chunk = f.read(1024)  # читать из файла не более 1024 байт
        if not chunk:  # файл закончился
            break
        while chunk and not chunk[-1].isspace():  # довычитывать слова целиком
            chunk += f.read(1)
        for w in filter(find_words.__contains__, set(chunk.split())):
            find_words.remove(w)  # слово найдено
            print('Вхождение есть для:', w)
if find_words:
    print('Вхождений нет для:', find_words)
→ Ссылка