Как мне повторно исследовать или заново сопоставлять весь файл, не считывая все это в память? - PullRequest
26 голосов
/ 18 января 2009

Я хочу иметь возможность запускать регулярные выражения для всего файла, но я бы хотел, чтобы мне не приходилось читать весь файл сразу в память, так как в будущем я могу работать с довольно большими файлами , Есть ли способ сделать это? Спасибо!

Уточнение: Я не могу прочитать построчно, потому что он может занимать несколько строк.

Ответы [ 8 ]

55 голосов
/ 18 января 2009

Вы можете использовать mmap для отображения файла в память. Затем к содержимому файла можно получить доступ как к обычной строке:

import re, mmap

with open('/var/log/error.log', 'r+') as f:
  data = mmap.mmap(f.fileno(), 0)
  mo = re.search('error: (.*)', data)
  if mo:
    print "found error", mo.group(1)

Это также работает для больших файлов, содержимое файла внутренне загружается с диска по мере необходимости.

5 голосов
/ 18 января 2009

Это зависит от файла и регулярного выражения. Лучшее, что вы можете сделать, это прочитать файл построчно, но если это не сработает в вашей ситуации, вы можете застрять с вытягиванием всего файла в память.

Скажем, например, что это ваш файл:

Lorem ipsum dolor sit amet, consectetur
adipiscing elit. Ut fringilla pede blandit
eros sagittis viverra. Curabitur facilisis
urna ABC elementum lacus molestie aliquet.
Vestibulum lobortis semper risus. Etiam
sollicitudin. Vivamus posuere mauris eu
nulla. Nunc nisi. Curabitur fringilla fringilla
elit. Nullam feugiat, metus et suscipit
fermentum, mauris ipsum blandit purus,
non vehicula purus felis sit amet tortor.
Vestibulum odio. Mauris dapibus ultricies
metus. Cras XYZ eu lectus. Cras elit turpis,
ultrices nec, commodo eu, sodales non, erat.
Quisque accumsan, nunc nec porttitor vulputate,
erat dolor suscipit quam, a tristique justo
turpis at erat.

И это было ваше регулярное выражение:

consectetur(?=\sadipiscing)

Теперь это регулярное выражение использует положительный прогноз и будет соответствовать только строке "consectetur", если за ним сразу следует какой-либо символ пробела, а затем строка "adipiscing".

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

Полагаю, неудачный ответ заключается в том, что все зависит от вашей ситуации.

2 голосов
/ 18 января 2009

Если это большое дело и стоит некоторых усилий, вы можете преобразовать регулярное выражение в конечный автомат, который читает файл. FSM может иметь сложность O (n), что означает, что он будет намного быстрее по мере увеличения размера файла.

Вы сможете эффективно сопоставлять шаблоны, которые охватывают строки в файлах, слишком больших для размещения в памяти.

Вот два места, которые описывают алгоритм для преобразования регулярного выражения в FSM:

2 голосов
/ 18 января 2009

Это один из способов:

import re

REGEX = '\d+'

with open('/tmp/workfile', 'r') as f:
      for line in f:
          print re.match(REGEX,line)
  1. с оператором в Python 2.5 выполняет автоматическое закрытие файла. Поэтому вам не нужно беспокоиться об этом.
  2. Итератор над файловым объектом экономит память. то есть он не будет читать больше строки памяти в данный момент времени.
  3. Но недостатком этого подхода является то, что для больших файлов потребуется много времени.

Другой подход, который приходит мне в голову, заключается в использовании методов read (size) и file.seek (offset), которые будут одновременно считывать часть размера файла.

import re

REGEX = '\d+'

with open('/tmp/workfile', 'r') as f:
      filesize = f.size()
      part = filesize / 10 # a suitable size that you can determine ahead or in the prog.
      position = 0 
      while position <= filesize: 
          content = f.read(part)
          print re.match(REGEX,content)
          position = position + part
          f.seek(position)

Вы также можете объединить эти два, там вы можете создать генератор, который будет возвращать содержимое определенных байтов в то время и выполнять итерацию по этому содержимому для проверки вашего регулярного выражения. Это ИМО было бы хорошим подходом.

1 голос
/ 15 февраля 2019

Здесь вы можете использовать re и mmap, чтобы найти все слова в файле, который не создает списки, или загрузить весь файл в память.

import re
from contextlib import closing
from mmap import mmap, ACCESS_READ

with open('filepath.txt', 'r') as f:
    with closing(mmap(f.fileno(), 0, access=ACCESS_READ)) as d:
        print(sum(1 for _ in re.finditer(b'\w+', d)))

на основе @ sth's ответа , но с меньшим использованием памяти

0 голосов
/ 18 января 2015
f = open(filename,'r')
  for eachline in f:
    string=re.search("(<tr align=\"right\"><td>)([0-9]*)(</td><td>)([a-zA-Z]*)(</td><td>)([a-zA-Z]*)(</td>)",eachline)
    if string:
      for i in range (2,8,2):
        add = string.group(i)
        l.append(add)
0 голосов
/ 18 января 2009

Откройте файл и выполните итерации по строкам.

fd = open('myfile')
for line in fd:
    if re.match(...,line)
        print line
0 голосов
/ 18 января 2009

Для однострочных шаблонов вы можете перебирать строки файла, но для многострочных шаблонов вам придется читать весь (или часть, но это будет трудно отследить) файла в память .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...