Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/344.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/27.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Python中的流数据中增量查找正则表达式匹配项_Python_Regex_Stream - Fatal编程技术网

在Python中的流数据中增量查找正则表达式匹配项

在Python中的流数据中增量查找正则表达式匹配项,python,regex,stream,Python,Regex,Stream,我将数据连续地流到多个TCP套接字中。对于每一个,我都有一个不同的正则表达式,需要为其提取匹配项。例如,可以匹配格式为###.#后跟字母f的数字: r = re.compile(rb'([0-9][0-9]\.[0-9])f') 另一个可能与前面有字母Q的格式###的数字匹配: r = re.compile(rb'Q([0-9][0-9][0-9])') 实际上,表达式可能具有任意长度和复杂性,并且是从配置文件中提取的,事先不知道。它们不是硬编码的 当新数据进入时,我将其附加到类型为byte

我将数据连续地流到多个TCP套接字中。对于每一个,我都有一个不同的正则表达式,需要为其提取匹配项。例如,可以匹配格式为###.#后跟字母f的数字:

r = re.compile(rb'([0-9][0-9]\.[0-9])f')
另一个可能与前面有字母Q的格式###的数字匹配:

r = re.compile(rb'Q([0-9][0-9][0-9])')
实际上,表达式可能具有任意长度和复杂性,并且是从配置文件中提取的,事先不知道。它们不是硬编码的

当新数据进入时,我将其附加到类型为
bytearray()
(这里称为
self.buffer
)的缓冲区中。然后我调用这样一个函数(其中
self.r
是编译后的正则表达式):

如果还没有匹配项,则返回None。如果存在匹配项,它将返回匹配项并丢弃缓冲区,直到匹配项结束,使自己准备好再次调用

然而,这种方法并不是特别有效。问题是,必须从一开始就一次又一次地扫描缓冲区——每当有新数据进入——直到找到匹配项。这可能需要重复扫描数千次和数百万个字符,然后才能找到匹配项并提前启动缓冲区

我不能在找到匹配项之前简单地丢弃缓冲区的内容,因为匹配项可能需要缓冲区的最后几个字节(甚至整个缓冲区)。一旦有更多的数据进入,缓冲区的结尾可能就是匹配的开始

如何重写我的“advance”函数以安全地丢弃缓冲区中不可能包含正则表达式开头的部分,从而不必重复扫描整个缓冲区

一种可能性是:如果没有找到匹配项的原因是因为到达了字符串的末尾,那么是否有一种替代“搜索”的方法返回“无”以外的内容?如果是这样,我能得到潜在匹配的起始位置吗?这将允许我丢弃缓冲区到那个点

另一种可能性是:某种类型的库足够聪明,可以重写任意正则表达式,这样它们就可以在截断的字符串上以一种不同的、可检测的方式进行匹配

我也会考虑其他可能性,但它们确实需要使用任意正则表达式,而不仅仅是上面简单的正则表达式。理想情况下,它们也不会涉及两次扫描缓冲区(一次是查找实际的潜在匹配,一次是丢弃内容)。

第三方模块(不是
re
)提供部分匹配支持,这是一种部分解决方案。(Lookbehinds、
^
锚定、零宽度匹配和
\b
/
\b
锚定在您尝试放弃窗口开始并继续搜索时都以微妙或不太微妙的方式断开。到目前为止,我已经想到了多少边缘情况,如果有更多,我不会感到惊讶。)

如果将
partial=True
传递给
regex.match
regex.search
regex.fullmatch
regex.finditer
,则除了报告普通的、完整的匹配之外,它还将报告不匹配的内容,但如果字符串被扩展,则可能:

In [8]: import regex

In [9]: regex.search(r'1234', '', partial=True)
Out[9]: <regex.Match object; span=(0, 0), match='', partial=True>

In [10]: regex.search(r'1234', '12', partial=True)
Out[10]: <regex.Match object; span=(0, 2), match='12', partial=True>

In [11]: regex.search(r'1234', '12 123', partial=True)
Out[11]: <regex.Match object; span=(3, 6), match='123', partial=True>

In [12]: regex.search(r'1234', '1234 123', partial=True)
Out[12]: <regex.Match object; span=(0, 4), match='1234'>
如果更多数据可能会更改匹配结果,则会将匹配报告为部分匹配:

In [21]: regex.search(r'.*', 'asdf', partial=True)
Out[21]: <regex.Match object; span=(0, 4), match='asdf', partial=True>

In [22]: regex.search(r'ham(?: and eggs)?', 'ham', partial=True)
Out[22]: <regex.Match object; span=(0, 3), match='ham', partial=True>
[21]中的
regex.search(r'.*',asdf',partial=True)
出[21]:
在[22]中:正则表达式搜索(r'ham(?:and eggs)?,'ham',partial=True)
出[22]:
或者如果更多数据可能导致匹配不匹配:

In [23]: regex.search(r'1(?!234)', '1', partial=True)
Out[23]: <regex.Match object; span=(0, 1), match='1', partial=True>

In [24]: regex.search(r'1(?!234)', '13', partial=True)
Out[24]: <regex.Match object; span=(0, 1), match='1'>
[23]中的
regex.search(r'1(?!234)'1',partial=True)
出[23]:
在[24]中:正则表达式搜索(r'1(?!234)'13',partial=True)
出[24]:
当您到达数据流的末尾时,应该关闭
partial
,让
regex
知道这是结尾,这样partial matches就不会隐藏完整的匹配


使用部分匹配信息,您可以放弃部分匹配开始之前的所有内容,并知道所有被丢弃的数据都不会出现在匹配中。。。但是lookbehinds可能需要这些数据,所以如果你这样做的话,需要额外的工作来支持lookbehinds
^
也会被字符串更改的开始部分弄糊涂,
\b
/
\b
不会知道丢弃数据的末尾是否有单词字符,而且无论您选择的“correct”的定义如何,都很难获得零宽度匹配行为的正确性。我怀疑,如果您以这种方式丢弃数据,其他一些高级功能
regex
也可能会产生奇怪的交互
regex
有很多特性。

不幸的是,在Python中没有将regex应用于流数据的好方法
re
需要一次将所有数据存储在内存中。你甚至不能假设当你在部分数据上找到一个匹配项时你可以提前缓冲,因为如果你有所有的数据,你可能会找到一个不同的匹配项,或者如果正则表达式中有令人讨厌的头像,它甚至不会是一个匹配项。使用
re
API,没有办法确定。模块(第三方库,不是
re
)支持部分匹配,这解决了其中一些问题,但我认为它们不能解决查找错误匹配的问题,我不知道它们如何处理查找。如果正则表达式真的那么简单,听起来您可能想编写一个简单的自定义解析器。@user2357112,
regex
模块正是我想要的。我对查找部分匹配没有意见,因为我可以记录这一点,用户在编写正则表达式时只需考虑这一点。它与当前的行为没有什么不同,但应该更有效。如果你把它作为一个答案,我会接受的。我不断地提出更多的东西,手动窗口处理打破
regex的部分匹配支持可能仍然是当前应用regex的最佳选择
In [21]: regex.search(r'.*', 'asdf', partial=True)
Out[21]: <regex.Match object; span=(0, 4), match='asdf', partial=True>

In [22]: regex.search(r'ham(?: and eggs)?', 'ham', partial=True)
Out[22]: <regex.Match object; span=(0, 3), match='ham', partial=True>
In [23]: regex.search(r'1(?!234)', '1', partial=True)
Out[23]: <regex.Match object; span=(0, 1), match='1', partial=True>

In [24]: regex.search(r'1(?!234)', '13', partial=True)
Out[24]: <regex.Match object; span=(0, 1), match='1'>