【问题标题】:regular expression on stream instead of string?流上的正则表达式而不是字符串?
【发布时间】:2012-10-11 20:17:19
【问题描述】:

假设你想在管道上进行正则表达式搜索和提取,但模式可能跨越多行,怎么做?也许正则表达式库适用于流?

我希望使用 Python 库来完成这项工作?但是任何解决方案都可以,当然是库而不是命令行工具。

顺便说一句,我知道如何解决我目前的问题,只是寻求一个通用的解决方案。

如果不存在这样的库,为什么常规库不能与流一起使用,因为常规数学算法从不需要向后扫描。

【问题讨论】:

  • 您能发布一些示例输入和您的预期输出吗?
  • 您可以跨行进行正则表达式匹配,但通常情况下,您需要所有内容都在那里才能进行匹配。

标签: python regex


【解决方案1】:

如果您寻求通用解决方案,您的算法需要如下所示:

  1. 将流的一部分读入缓冲区。
  2. 在缓冲区中搜索正则表达式
  3. 如果模式匹配,对匹配做任何你想做的事情,丢弃缓冲区的开头直到match.end(),然后转到第 2 步。
  4. 如果模式不匹配,请使用流中的更多数据扩展缓冲区

如果没有找到匹配项,这最终可能会占用大量内存,但在一般情况下很难做得更好(考虑尝试将 .*x 匹配为大文件中的多行正则表达式,其中唯一的x 是最后一个字符)。

如果您对正则表达式有更多了解,您可能会遇到其他可以丢弃部分缓冲区的情况。

【讨论】:

  • 看看@ITNinja 的回答,我给出的算法也不完美。例如,如果您有一个表达式x* 并且缓冲区以x 结尾,那么如果流包含更多x 字符,则该算法可能会给您错误的匹配。希望这足以让您了解如何使用re 库处理此类情况。
  • 现在我明白了@ITNinja 的观点。事实上,一旦出现'.*',所有的流很可能都需要被缓冲。但是,如果设计得当,在流上工作的库仍然具有优势,它们通过管道数据生成和匹配。但是正确的实现需要在较低级别重写 RE 库,这超出了我的能力和能力。
  • 我刚刚找到了另一个解决方案:pexpect pexpect.readthedocs.org/en/latest/api/pexpect.html
  • @GiovanniFunchal 我看不出您的 pexpect 链接与 OP 的问题有什么关系
  • pexpect 是一个 python 库。您可以将 OP 拥有的管道的文件描述符传递给它,然后您可以使用 .expect() 和正则表达式进行解析。 pexpect 添加的值是为您处理管道的缓冲和阻塞。
【解决方案2】:

我解决了使用经典模式匹配搜索流的类似问题。您可能想要继承我的解决方案 streamsearch-py 的 Matcher 类并在缓冲区中执行正则表达式匹配。查看下面包含的 kmp_example.py 以获取模板。如果事实证明经典的 Knuth-Morris-Pratt 匹配就是您所需要的,那么您的问题现在就可以通过这个小型开源库得到解决了 :-)

#!/usr/bin/env python

# Copyright 2014-2015 @gitagon. For alternative licenses contact the author.
# 
# This file is part of streamsearch-py.
# streamsearch-py is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# 
# streamsearch-py is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.
# You should have received a copy of the GNU Affero General Public License
# along with streamsearch-py.  If not, see <http://www.gnu.org/licenses/>.


from streamsearch.matcher_kmp import MatcherKMP
from streamsearch.buffer_reader import BufferReader

class StringReader():
    """for providing an example read() from string required by BufferReader"""
    def __init__(self, string):
        self.s = string
        self.i = 0

    def read(self, buf, cnt):
        if self.i >= len(self.s): return -1
        r = self.s[self.i]
        buf[0] = r
        result = 1
        print "read @%s" % self.i, chr(r), "->", result
        self.i+=1
        return result

def main():

    w = bytearray("abbab")
    print "pattern of length %i:" % len(w), w
    s = bytearray("aabbaabbabababbbc")
    print "text:", s
    m = MatcherKMP(w)
    r = StringReader(s)
    b = BufferReader(r.read, 200)
    m.find(b)
    print "found:%s, pos=%s " % (m.found(), m.get_index())


if __name__ == '__main__':
    main()

输出是

pattern of length 5: abbab
text: aabbaabbabababbbc
read @0 a -> 1
read @1 a -> 1
read @2 b -> 1
read @3 b -> 1
read @4 a -> 1
read @5 a -> 1
read @6 b -> 1
read @7 b -> 1
read @8 a -> 1
read @9 b -> 1
found:True, pos=5 

【讨论】:

  • 虽然此链接可能会回答问题,但最好在此处包含答案的基本部分并提供链接以供参考。如果链接页面发生更改,仅链接的答案可能会失效。
  • 真的。粘贴kmp_example.py
【解决方案3】:

我不相信可以在流上使用正则表达式,因为没有整条数据,您无法进行肯定匹配。这意味着你只会有一个可能的匹配。

但是,正如@James Henstridge 所说,您可以使用缓冲区来克服这个问题。

【讨论】:

  • 这听起来不正确。一个简单的正则表达式是一个 DFA。每个输入字符都是该 DFA 中的一个状态转换。特定的转换表示匹配。除非有高级功能或实现性能限制,否则不需要完整的字符串来评估字符串上的 DFA。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-26
  • 2013-10-06
  • 2015-06-12
  • 2014-09-01
  • 1970-01-01
  • 2011-02-19
相关资源
最近更新 更多