Поиск слов из списка в большом файле (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 шт):
Пример использования регулярок:
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
в конце, поэтому я большие буквы брать не стал. Лучше всё-таки выяснить, какой на самом деле формат этого файла, это явно двоичный формат, в котором данные вперемешку лежат текстовые и не текстовые.
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}')
Алгоритм Ахо-Корасик позволяет задать набор паттернов для поиска, и пройти по строкам, находя совпадения со всеми паттернами сразу (ещё один алгоритм с подобными свойствами - Commentz-Walter).
Библиотеки для Python c реализацией этого алгоритма есть, вот первое из поиска
Если у вас есть проблемы с интерпретацией бинарного файла как текстового (данные "портятся"), то ничего не мешает применить тот же алгоритм к файлу как набору байтов (вот какая-то простая реализация, в которой можно поменять строки на списки или массивы байтов)
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)