Kan*_* Li 13 python regex python-2.7
我有一个类似序列的自定义对象s,该对象继承collections.Sequence并实现了custom __len__和__getitem__。它代表一大串字符串(> 4GB),并且延迟加载(我无法负担全部加载到内存中)。
我想对它进行RE匹配re.compile('some-pattern').match(s),但是失败了TypeError: expected string or buffer。
在实践中,模式并不是'.*'需要整个s加载的东西。通常需要前几十个字节来匹配;但是,我无法事先告知确切的字节数,并且我希望将其保持通用,因此我不想做类似的事情re.compile('some-pattern').match(s[:1000])。
关于如何创建str被接受的类似对象的任何建议re?
以下代码说明了我的失败尝试。继承str也不起作用。
In [1]: import re, collections
In [2]: class MyStr(collections.Sequence):
def __len__(self): return len('hello')
def __getitem__(self, item): return 'hello'[item]
...:
In [3]: print(re.compile('h.*o').match(MyStr()))
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-3-df08913b19d7> in <module>()
----> 1 print(re.compile('h.*o').match(MyStr()))
TypeError: expected string or buffer
Run Code Online (Sandbox Code Playgroud)
如果字符串的一大团来自单个大文件,那么我可以使用mmap它,它应该可以工作。但是,我的情况比较复杂。我有多个大文件,mmap每个文件都有一个,并有一个自定义类,它们是它们的串联视图。我实际上想从视图中的任何给定位置开始执行RE匹配。我在原始问题中忽略了这些细节,但是对于想了解为什么我有这样奇怪要求的人来说,这可能会有所帮助。
Mar*_*ers 11
有没有你可以实现将让特殊的方法re.match()接受您的自定义类,而不是要求您阅读所有的数据到内存中。
这是因为当前没有特殊的方法可以让您的自定义类充当缓冲区协议对象。re方法仅接受str字符串(确实实现了缓冲协议)和unicode字符串(和子类,直接访问数据,而不通过__unicode__)。这些re方法不接受任意序列,只有缓冲区协议可以让您避免一次性将整个内容读入内存。
但是,如果您的数据完全存储在单个磁盘文件中(但是太大而无法读入内存),则可以使用内存映射,而不是尝试实现自定义对象。内存映射使用操作系统的虚拟内存功能来访问文件的一部分作为内存部分。
通过将内存块(“页面”)放置在硬盘上,虚拟内存子系统使您的OS可以管理的内存比计算机以RAM形式实际可用的更多内存。在访问内存时,操作系统会不断将页面从磁盘换出到物理内存,然后再换回来。内存映射只是将此功能扩展到现有文件,从而可以将非常大的文件视为单个大字符串,操作系统将确保您需要访问的部分在内存中可用。
在Python中,此功能可通过mmap模块使用,而内存映射文件则实现了缓冲区协议。您可以将此类对象直接传递给re.match(),Python和您的操作系统将协同工作以在文件中搜索数据以进行匹配。
因此,给定一个大文件filename = '/path/to/largefile'和正则表达式pattern,这将在文件的开头搜索您的模式的匹配项:
import re
import mmap
import os
fd = os.open(filename, os.O_RDONLY)
mapped = mmap.mmap(fd, 0)
matched = re.match(pattern, mapped)
Run Code Online (Sandbox Code Playgroud)
如果您有多个文件,则需要找到一种方法来串联它们。虚拟地或物理地。如果您使用的是Linux,则可以使用网络块设备虚拟连接文件,也可以使用FUSE虚拟文件系统。请参阅包含其他文件串联的虚拟文件。