我希望能够在整个文件上运行正则表达式,但我希望能够不必立即将整个文件读入内存,因为我将来可能会使用相当大的文件。有没有办法做到这一点?谢谢!
澄清:我无法逐行阅读,因为它可以跨越多行。
答案 0 :(得分:55)
您可以使用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)
这也适用于大文件,文件内容根据需要从磁盘内部加载。
答案 1 :(得分:5)
这取决于文件和正则表达式。您可以做的最好的事情是逐行读取文件,但如果这对您的情况不起作用,则可能会因将整个文件拉入内存而陷入困境。
让我们举例说这是你的文件:
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)
现在这个正则表达式使用positive lookahead并且只会匹配一串“consectetur”,如果它后面跟着任何空格字符,然后是一个“adipiscing”字符串。
因此,在此示例中,您必须将整个文件读入内存,因为正则表达式取决于整个文件被解析为单个字符串。这是许多示例中需要您将整个字符串放在内存中以使特定正则表达式工作的示例之一。
我想不幸的答案是,这完全取决于你的情况。
答案 2 :(得分:2)
这是一种方式:
import re
REGEX = '\d+'
with open('/tmp/workfile', 'r') as f:
for line in f:
print re.match(REGEX,line)
我想到的另一种方法是使用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)
您还可以将这两者组合在一起,您可以创建生成器,该生成器会在当时返回内容某个字节并迭代该内容以检查您的正则表达式。这个IMO将是一个很好的方法。
答案 3 :(得分:2)
如果这是一个大问题并且值得付出一些努力,您可以将正则表达式转换为读取文件的有限状态机。 FSM可能具有O(n)复杂度,这意味着随着文件大小变大,FSM会更快。
您将能够有效地匹配跨越文件中的行的模式,这些模式太大而无法存储在内存中。
以下是描述将正则表达式转换为FSM的算法的两个地方:
答案 4 :(得分:1)
这里有一个选项供您使用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的answer,但内存使用量较少
答案 5 :(得分:0)
对于单行模式,您可以遍历文件的行,但是对于多行模式,您必须将文件的所有(或部分,但很难跟踪)读入内存
答案 6 :(得分:0)
打开文件并遍历这些行。
fd = open('myfile')
for line in fd:
if re.match(...,line)
print line
答案 7 :(得分:0)
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)
答案 8 :(得分:0)
Python 3: 要使用一个大字符串加载文件,请使用read()和encode()方法
import re, mmap
def read_search_in_file(file):
with open('/var/log/error.log', 'r+') as f:
data = mmap.mmap(f.fileno(), 0).read().decode("utf-8")
error = re.search(r'error: (.*)', data)
if error:
return error.group(1)