用于自定义序列类型的Python re

用于自定义序列类型的Python re,python,regex,python-2.7,Python,Regex,Python 2.7,我有一个自定义序列,比如对象s,它继承了集合。序列,并实现了自定义\uu len\uuu和\uu getitem\uuu。它代表一大串字符串(>4GB),并且是延迟加载的(我负担不起将所有字符串加载到内存中) 我想对它进行重新匹配,RE.compile('some-pattern').match(s),但是它失败了,出现了TypeError:expected string或buffer 实际上,模式并不是像'.*那样需要加载整个s;它通常需要前几十个字节来匹配;然而,我不能预先知道确切的字节数,

我有一个自定义序列,比如对象
s
,它继承了
集合。序列
,并实现了自定义
\uu len\uuu
\uu getitem\uuu
。它代表一大串字符串(>4GB),并且是延迟加载的(我负担不起将所有字符串加载到内存中)

我想对它进行重新匹配,
RE.compile('some-pattern').match(s)
,但是它失败了,出现了
TypeError:expected string或buffer

实际上,模式并不是像
'.*
那样需要加载整个
s
;它通常需要前几十个字节来匹配;然而,我不能预先知道确切的字节数,我希望保持它的通用性,因此我不想做类似于
re.compile('some-pattern').match(s[:1000])
的事情

关于如何创建被
re
接受的类似
str
的对象,有什么建议吗


下面的代码说明了我失败的尝试。从
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
[1]中的
:导入re、集合
在[2]中:类MyStr(collections.Sequence):
定义len(self):返回len('hello')
def\uu getitem(self,item):返回“hello”[项目]
...:
在[3]中:打印(重新编译('h.*o').match(MyStr()))
---------------------------------------------------------------------------
TypeError回溯(最近一次调用上次)
在()
---->1个打印(重新编译('h.*o').match(MyStr()))
TypeError:应为字符串或缓冲区

如果大字符串块来自单个大文件,那么我可以使用
mmap
,它应该可以工作。然而,我的情况更复杂。我有多个大文件,我
mmap
编辑了每个文件,并有一个自定义类,该类是它们的串联视图。实际上,我希望从视图中的任何给定位置开始执行重新匹配。我在最初的问题中省略了这些细节,但我认为这可能有助于理解我为什么有如此奇怪的要求的人。

没有可以实现的特殊方法,可以让
re.match()
接受自定义类,而不需要将所有数据读入内存

这是因为目前没有特殊的方法可以让自定义类充当
re
方法仅接受
str
字符串(实现缓冲区协议)和
unicode
字符串(以及子类,直接访问数据,而不是通过
\uuuuuunicode\uuuunicode
)。
re
方法不接受任意序列,只有缓冲协议才能避免一次性将整个内容读入内存

但是,如果您的数据完全存储在一个磁盘文件中(但太大而无法读入内存),您不需要尝试实现自定义对象,而是希望使用。内存映射使用操作系统的虚拟内存设施来访问文件的部分作为内存的一部分

虚拟内存子系统通过将内存块(“页面”)放在硬盘上,让操作系统以RAM的形式管理比计算机实际可用内存更多的内存。当访问内存时,操作系统不断地将页面从磁盘交换到物理内存,然后再交换回来。内存映射只是将此功能扩展到现有文件,从而可以将非常大的文件视为单个大字符串,操作系统将确保您尝试访问的部分在需要时在内存中可用

在Python中,此功能通过提供,并且内存映射文件is实现缓冲区协议。您可以将这些对象直接传递给
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)

如果您有多个文件,您需要找到一种方法来连接它们。虚拟的,或物理的。如果您使用的是Linux,则可以使用网络块设备虚拟连接文件,也可以使用FUSE虚拟文件系统。请参阅。

您是否也有磁盘限制?如果磁盘大小不是问题,您可以将所有文件临时连接到一个文件中,然后
mmap
将其搜索。从
str
继承适用于我:
class(str):pass\n c=class('hello')\n re.compile('h.'o')。match(c)
您能说明为什么它不适用于您吗?@zwer,连接所有文件不是一个选项。太慢了。@Sanyash,在你的代码中,它基本上是在构造字符串之前将整个字符串加载到内存中。这不是我的选择。在这种情况下,实现这一点并捕获跨越文件边界的匹配的唯一真正方法是不使用python,而是使用命令行工具,如
cat
grep
。或者找到某种方法或者保证永远不会有跨越文件边界的匹配项(可能是不包含新行字符的正则表达式,并且所有文件都必须以换行符结尾)。感谢您提供的信息。实际上,我在原始问题的最后一段提到了mmap,我确实需要能够在多个文件的串联上运行。我想确认一下,在纯python中无法实现缓冲区协议对象,对吗?@KanLi缓冲区协议的问题是它不是基于迭代的——它假设一些连续的内存块,其中数据以固定的步幅分散。如果缓冲区允许多个内存块,那么您可以
mmap
多个文件,并将它们的内存区域包装在这样一个超级缓冲区结构中。@KanLi:buffer协议专门处理连续内存;协议定义了起始地址和长度(数据本身是一个可以是多维的数组,当然