流数据的高效(基本)正则表达式实现
Posted
技术标签:
【中文标题】流数据的高效(基本)正则表达式实现【英文标题】:Efficient (basic) regular expression implementation for streaming data 【发布时间】:2012-10-02 20:12:57 【问题描述】:我正在寻找一种对数据流进行操作的正则表达式匹配的实现——即,它有一个 API,允许用户一次传入一个字符并在找到匹配项时报告到目前为止看到的字符流。只需要非常基本(经典)的正则表达式,因此基于 DFA/NFA 的实现似乎非常适合该问题。
基于可以在单次线性扫描中使用 DFA/NFA 进行正则表达式匹配的事实,流式实现似乎应该是可能的。
要求:
库应该不尝试等到完整的字符串被读取后再执行匹配。我真正拥有的数据是流式传输的;没有办法知道有多少数据会到达,不可能向前或向后搜索。
为几个特殊情况实施特定的流匹配不是一种选择,因为我事先不知道用户可能想要寻找什么模式。
语言:可用于 C/C++
出于好奇,我的用例如下:我有一个在完整系统模拟器中拦截内存写入的系统,我想有一种方法来识别与正则表达式匹配的内存写入(例如,可以使用它来查找系统中将 URL 写入内存的点)。
我找到了:
Apply a Regex on Stream?
Applying a regular expression to a Java I/O Stream
Code Guru - Building a Regular Expression Stream Search with the .NET Framework
但所有这些都试图先将流转换为字符串,然后使用常用的正则表达式库。
我的另一个想法是修改RE2 library,但according to the author 是围绕整个字符串同时在内存中的假设构建的。
如果没有可用的东西,那么我可以开始重新发明这个***以满足我自己的需求的不幸道路,但如果我可以避免它,我真的宁愿不这样做。任何帮助将不胜感激!
【问题讨论】:
你说必须读取完整的字符串,然后才能读取整个流并存储处理? 抱歉,这是一个错误的错字。数据是流式传输的,我们不能等到最后才处理它(通过的数据总量超过 100 GB)。 这是一个幼稚的解决方案,但您始终可以保留流的最后 n 个字节的缓冲区并对其应用正则表达式。根据您的要求,它可能适合您。 【参考方案1】:看看Brian W. Kernighan and Rob Pike 中类似这样的旧 grep 实现。它们在缓冲区中处理文本流,并应用于简单的正则表达式规则,甚至不是 BRE。
【讨论】:
【参考方案2】:不幸的是,这个问题的“答案”是没有预先构建的库来执行此操作。相反,我选择了以下折衷方案:我实现了一个简单的字符串匹配器(不支持 RE),它使用每个流和每个搜索字符串的单个计数器来保持状态,该计数器跟踪在该流中匹配了多少个搜索字符串的字符。它随着每个正确的字符而增加,并在找到不匹配的字符时重置为零。这速度很快,并且不需要太多的内存开销。
对于更复杂的搜索,我只是将所有流转储到磁盘,然后使用传统工具搜索它们。它非常慢,但幸运的是,我们的大多数用例都可以通过简单的字符串匹配来解决。
【讨论】:
【参考方案3】:我有你要找的东西:https://github.com/agentzh/sregex http://agentzh.org/misc/slides/yapc-na-2013-sregex.pdf
如果你知道 javascript(或想要一个 javascript 版本),我有一个练习可以让你使用现有的 RE 实现轻松做到这一点:https://github.com/dhruvbird/regexp-js
【讨论】:
感谢您发布此信息! :) 您的库是否可以在浏览器中使用?我不确定如何处理require
s。
@Mehrdad 您应该能够通过微小的更改使其在浏览器中工作。我首先在浏览器中对其进行了测试。我不确定浏览器中的需求是如何产生的,但 underscore.js 在浏览器中是可用的。
顺便说一下好像没有实现DFA搜索。是我想念它还是真的不存在?
奇怪,那this statement为什么是空的?
啊!我记得。我认为我还没有完全弄清楚如何使用 DFA 匹配来实现子匹配捕获,所以我没有充实它。如果您以直接的方式实现它,那么没有捕获的部分应该可以工作。【参考方案4】:
英特尔已经发布了 hyperscan 库,它完全可以满足需要。 Here 是它的简要概述。
【讨论】:
以上是关于流数据的高效(基本)正则表达式实现的主要内容,如果未能解决你的问题,请参考以下文章