2016-02-28 59 views
1

我想以最低的开发成本将re模块与流(但不一定是文件流)一起使用。纯Python3中类似Mmap的行为

对于文件流,有mmap模块可以模拟字符串,因此可以自由使用re

现在我想知道mmap如何管理一个对象,re可以进一步重用。如果我只是通过任何方式,re保护自己免受使用与TypeError: expected string or bytes-like object太不兼容的对象。所以我想我会创建一个派生自stringbytes的类,并覆盖一些方法,如__getitem__等(这直观地适合Python的鸭子打字理念),并使它们与我的原始流进行交互。但是,这似乎并不奏效 - 我的覆盖被完全忽略。

是否有可能在纯Python中创建这样一个“懒惰”的string,没有C扩展?如果是这样,怎么样?

一点背景无视替代解决方案:

  • 不能使用mmap(流内容不是文件)
  • 不能放弃整个事情的HDD(太慢)
  • 无法加载整个事情
  • 可以寻求内存(太大),知道大小和计算在运行时的内容

示例代码,演示了修改bytes阻力:

class FancyWrapper(bytes): 
    def __init__(self, base_str): 
     pass #super() isn't called and yet the code below finds abc, aaa and bbb 

print(re.findall(b'[abc]{3}', FancyWrapper(b'abc aaa bbb def'))) 
+0

什么__你的流?你可以发布你尝试从'str'派生出来的代码吗? – bbayles

+0

@bbayles我的流包含“数据范围” - 每个“数据范围”可能从内存或硬盘上的文件中获取数据。当要求特定偏移量的数据时,有一项功能可将来自此类距离偏移的信息组合到一个线性内存中。基本上这是一个处理编辑大文件的方法。编辑该帖子以提供最基本的示例。 –

+0

也许我很厚,但请详细说明为什么你不能简单地迭代你的流?对于任何文件,我们都会在fh中做一个'for line:... re.search(line,pattern)...'。对于文件以外的其他内容,使用简单的代码模式,例如[this this for string streams](http://stackoverflow.com/questions/21843693/creating-stream-to-iterate-over-from-string-in-python)。如果您可以查找您的数据,这应该很容易实现。 – cfi

回答

1

好吧,我发现这是不可能的,而不是目前。

  1. Python的re模块在内部上的意义上的字符串操作它所扫描通过一个普通的C缓冲区,这需要它接收到满足这些属性的对象:

    • 其表示必须驻留在系统内存,
    • 他们的表示必须是线性的,例如它不能包含任何类型的空白,
    • 它们的表示必须包含我们整体搜索的内容。

    所以即使我们设法与比bytesstring别的东西re工作,我们不得不使用mmap般的行为,即冒充我们的内容提供商,如系统内存线性区。

  2. mmap机制将工作只有的文件,事实上,即使这也是相当有限。例如,根据this answer,如果有人试图写入大文件,则不能写入大文件。

  3. 即使regex模块,其中包含许多超级骗子加成如(?r),并不适应外界stringbytes内容源。

为了完整:这是否意味着,我们就完蛋了,并且可以通过大动态内容与re不扫描?不必要。如果我们允许最大匹配大小的限制,有一种方法可以做到这一点。该解决方案受cfi的评论启发,并将其扩展为二进制文件。

  1. n =最大匹配大小。
  2. 开始在位置搜索X
  3. 虽然没有内容:
    1. 导航定位X
    2. 2 * N字节扫描缓冲
    3. 查找内的第一场比赛扫描缓冲区
    4. 如果找到匹配项:
      1. X = X + match_pos + match_size
      2. 通知有关match_posmatch_size
    5. 如果比赛没有被发现:
      1. X = X + n

这是通过使用两倍大的缓冲区作为最大匹配大小来实现的吗?试想一下,用户搜索A{3}和最大匹配长度设置为3。如果我们想在目前的X包含AABBBA阅读只是最大匹配长度字节扫描缓冲区和数据:

  1. 这迭代将看AAB。没有匹配。
  2. 下一次迭代会将指针移动到x + 3
  3. 现在扫描缓冲区看起来像这样:BBA。仍然没有匹配。

这显然是不好的,简单的解决方法是读取两倍的字节数,以确保扫描缓冲区尾部附近的异常得到解决。

请注意,扫描缓冲区内第一次匹配时的短路应该能够防止其他异常情况,例如缓冲区下陷。它可能会被调整,以尽量减少包含多个匹配的扫描缓冲区的读取,但我想避免更复杂的事情。

这可能不是最高性能的算法,但对我的用例足够好,所以我将它留在这里。