En el caso específico de un archivo, si puede memoria- mapee el archivo con mmap
y si está trabajando con cadenas de bytes en lugar de Unicode, puede alimentar un archivo mapeado en memoria al re
como si fuera una cadena de bytes y simplemente funcionará. Esto está limitado por su espacio de direcciones, no por su RAM, por lo que una máquina de 64 bits con 8 GB de RAM puede mapear en memoria un archivo de 32 GB sin problemas.
Si puede hacerlo, es una buena opción. Si no puede, tiene que recurrir a opciones más complicadas.
El regex
módulo 3 ª parte (no re
) ofrece apoyo coincidencia parcial, que puede ser utilizado para construir el soporte de streaming ... pero es complicado y tiene un montón de advertencias. Cosas como lookbehinds y ^
no funcionarán, las coincidencias de ancho cero serían difíciles de hacer, y no sé si interactuarían correctamente con otras características avanzadas regex
ofertas y re
no. Aún así, parece ser lo más parecido a una solución completa disponible.
Si pasa partial=True
a regex.match
, regex.fullmatch
, regex.search
, o regex.finditer
, a continuación, además de informar partidos completos, regex
también informará cosas que podrían ser un partido si los datos se amplió:
In [10]: regex.search(r'1234', '12', partial=True)
Out[10]: <regex.Match object; span=(0, 2), match='12', partial=True>
Se Informará una coincidencia parcial en lugar de una coincidencia completa si más datos pueden cambiar el resultado del partido, por lo que, por ejemplo, regex.search(r'[\s\S]*', anything, partial=True)
siempre será una coincidencia parcial.
Con esto, puede mantener una ventana deslizante de datos para que coincida, ampliándola al llegar al final de la ventana y descartando los datos consumidos desde el principio. Desafortunadamente, cualquier cosa que se confunda por la desaparición de los datos desde el inicio de la cadena no funcionará, por lo tanto, mira hacia atrás, ^
, \b
, y \B
están fuera. Las coincidencias de ancho cero también necesitarían un manejo cuidadoso. Aquí hay una prueba de concepto que utiliza una ventana deslizante sobre un archivo o un objeto similar a un archivo:
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
eso va en contra de la idea de regex. – SilentGhost
@SlientGhost: No necesariamente. Es posible que desee analizar un flujo (infinito) utilizando expresiones regulares, siempre coincidiendo con el comienzo actual de la secuencia y devolver las coincidencias como un iterador (y consumir solo los caracteres combinados de la secuencia). – MartinStettner
@MartinStettner: Bueno, podría hacerlo si se tratara de un equilibrador de autómatas sin resúmenes (y algunas otras cosas también, como las limitaciones de anticipación). Siempre que el RE pueda compilarse a un único autómata finito (ya sea NFA o DFA), puede hacer coincidir las cosas en una pasada y, por lo tanto, puede manejar las coincidencias que coincidan con una secuencia infinita. (Pero Python usa PCRE, que no es una teoría de autómatas y necesita todos los bytes allí antes). –