В конкретном случае файла, если вы можете отобразить файл в памяти с помощью mmap
, и если вы работаете со строками байтов вместо Unicode, вы можете передать файл, отображенный в память, вre
как будто это строка байтов, и она будет просто работать.Это ограничено вашим адресным пространством, а не оперативной памятью, поэтому 64-разрядный компьютер с 8 ГБ ОЗУ может отображать в памяти файл размером 32 ГБ.
Если вы можете сделать это, это действительно хорошовариант.Если вы не можете, вы должны обратиться к более сложным опциям.
Сторонний модуль regex
(не re
) предлагает поддержку частичного соответствия, которая можетиспользоваться для создания поддержки потоковой передачи ... но это грязно и имеет много предостережений.Такие вещи, как lookbehinds и ^
не будут работать, совпадения нулевой ширины было бы непросто сделать правильно, и я не знаю, будет ли оно правильно взаимодействовать с другими расширенными функциями regex
предложениями, а re
- нет,Тем не менее, кажется, что это самое близкое решение к полному доступному решению.
Если вы передадите partial=True
на regex.match
, regex.fullmatch
, regex.search
или regex.finditer
, то в дополнение к отчетностиполные совпадения, regex
также сообщит о том, что может быть совпадением, если данные были расширены:
In [10]: regex.search(r'1234', '12', partial=True)
Out[10]: <regex.Match object; span=(0, 2), match='12', partial=True>
Он сообщит о частичном сопоставлении вместо полного совпадения, если больше данных может изменить результат совпадениятак, например, regex.search(r'[\s\S]*', anything, partial=True)
всегда будет частичным совпадением.
При этом вы можете сохранить скользящее окно данных для сопоставления, расширяя его, когда вы дойдете до конца окна, и отбрасывая использованные данные изначало.К сожалению, все, что может быть сбито с толку исчезновением данных в начале строки, не будет работать, поэтому lookbehinds, ^
, \b
и \B
отсутствуют.Совпадения с нулевой шириной также требуют осторожного обращения.Вот подтверждение концепции, которая использует скользящее окно над файлом или подобным файлу объектом:
import regex
def findall_over_file_with_caveats(pattern, file):
# Caveats:
# - doesn't support ^ or backreferences, and might not play well with
# advanced features I'm not aware of that regex provides and re doesn't.
# - Doesn't do the careful handling that zero-width matches would need,
# so consider behavior undefined in case of zero-width matches.
# - I have not bothered to implement findall's behavior of returning groups
# when the pattern has groups.
# Unlike findall, produces an iterator instead of a list.
# bytes window for bytes pattern, unicode window for unicode pattern
# We assume the file provides data of the same type.
window = pattern[:0]
chunksize = 8192
sentinel = object()
last_chunk = False
while not last_chunk:
chunk = file.read(chunksize)
if not chunk:
last_chunk = True
window += chunk
match = sentinel
for match in regex.finditer(pattern, window, partial=not last_chunk):
if not match.partial:
yield match.group()
if match is sentinel or not match.partial:
# No partial match at the end (maybe even no matches at all).
# Discard the window. We don't need that data.
# The only cases I can find where we do this are if the pattern
# uses unsupported features or if we're on the last chunk, but
# there might be some important case I haven't thought of.
window = window[:0]
else:
# Partial match at the end.
# Discard all data not involved in the match.
window = window[match.start():]
if match.start() == 0:
# Our chunks are too small. Make them bigger.
chunksize *= 2