Dans le cas spécifique d'un fichier, si vous pouvez Mappez le fichier avec mmap
et si vous travaillez avec des octets au lieu d'Unicode, vous pouvez envoyer un fichier mappé en mémoire à re
comme s'il s'agissait d'un octet et il fonctionnera. Ceci est limité par votre espace d'adressage, pas votre RAM, donc une machine 64 bits avec 8 Go de RAM peut très bien mapper un fichier de 32 Go.
Si vous pouvez le faire, c'est une très bonne option. Si vous ne pouvez pas, vous devez vous tourner vers des options plus désordonnées.
La 3ème partie Module regex
(non re
) offre un support de correspondance partielle, qui peut être utilisé pour construire un soutien continu ... mais il est en désordre et a beaucoup de mises en garde. Des choses comme lookbehinds et ^
ne fonctionnera pas, des allumettes de largeur nulle seraient difficiles à obtenir correctement, et je ne sais pas si cela interagirait correctement avec d'autres fonctionnalités avancées et re
et non regex
offres. Pourtant, il semble être la chose la plus proche d'une solution complète disponible.
Si vous passez partial=True
à regex.match
, regex.fullmatch
, regex.search
ou regex.finditer
, puis, en plus de rapports matchs complets, regex
rendra également compte des choses qui pourraient être un match si les données a été prolongée:
In [10]: regex.search(r'1234', '12', partial=True)
Out[10]: <regex.Match object; span=(0, 2), match='12', partial=True>
Il signalera une correspondance partielle au lieu d'une correspondance complète si plus de données peuvent modifier le résultat du match. Par exemple, regex.search(r'[\s\S]*', anything, partial=True)
sera toujours une correspondance partielle. Avec cette option, vous pouvez conserver une fenêtre de données glissante correspondant, en la prolongeant lorsque vous atteignez la fin de la fenêtre et en supprimant les données consommées depuis le début. Malheureusement, tout ce qui pourrait être perturbé par la disparition des données au début de la chaîne ne fonctionnera pas, donc les fenêtres de recherche, ^
, \b
, et \B
sont désactivées. Les allumettes à largeur nulle devraient également être manipulées avec soin. Voici une preuve de concept qui utilise une fenêtre glissante sur un fichier ou un objet de type fichier:
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
est contraire à l'idée de regex. – SilentGhost
@SlientGhost: Pas nécessairement. Vous pouvez analyser un flux (infini) en utilisant des regexes, toujours en correspondance avec le début courant du flux et renvoyer les correspondances en tant qu'élément d'itération (et en ne consommant que les caractères correspondants du flux). – MartinStettner
@MartinStettner: Eh bien, vous pourriez le faire si c'était un matcher automata-théorique sans backrefs (et quelques autres choses aussi, comme les contraintes de lookahead). Tant que le RE peut compiler vers un seul automate fini (NFA ou DFA), il peut correspondre à des choses en une seule passe et peut donc gérer des taches correspondant à un flux infini. (Mais Python utilise PCRE, qui n'est pas automate-théorétique et qui a besoin de tous les octets auparavant.) –