我正在寻找快速安全的方法在Streams上应用正则表达式。
我在互联网上找到了一些关于将每个缓冲区转换为String然后在字符串上应用Regex
的例子。
这种方法有两个问题:
Regex
,那么肯定可以避免。Regex
支持:Regex
模式有时只能将两个缓冲区组合在一起(缓冲区1以匹配的第一部分结束,缓冲区2以匹配的第二部分开始) 。转换为字符串的方式无法原生地处理这种类型的匹配,我必须提供更多信息,例如模式可以匹配的最大长度,这根本不支持+和*正则表达式标志,并且永远不会支持(无限制匹配)长度)。因此,转换为字符串的方式并不快,并且不完全支持Regex
。
是否有任何方法/库可用于在Streams上应用Regex
而无需转换为字符串并具有完整的Regex支持?
答案 0 :(得分:5)
英特尔最近在BSD许可下开源hyperscan库。这是一款基于NFA的高性能非回溯正则表达式引擎。
功能:能够处理输入数据流和同时进行多种模式匹配。最后一个与(pattern1|pattern2|...)
方法不同,它实际上是同时匹配模式。
它还利用了英特尔的SIMD指令集,如SSE4.2,AVX2和BMI。 可以找到here的设计和工作说明摘要。 它还有很棒的开发人员reference guide,有很多解释以及性能和使用注意事项。 小article关于在野外使用它(俄语)。
答案 1 :(得分:1)
您似乎想知道您想要获得的比赛的开始和结束分隔符,对吗? (即[,]或START,END等)因此,当您的流中的数据进入,然后在分隔符之间创建子字符串并对其进行进一步处理时,搜索这些分隔符是否有意义?
我知道它与滚动自己的东西几乎相同,但它将具有更具体的目的,甚至可以在它进入时进行处理。
此实例中正则表达式的问题在于它们基于匹配工作,因此您只能匹配您拥有的输入量。如果你有一个流,你必须读入所有数据以获得所有匹配(空间/时间约束问题),尝试在引入时匹配角色(相当无用),匹配块(再次,那些东西很容易被错过)或产生感兴趣的字符串,如果符合你的标准,可以从其他地方运出进行进一步处理。
答案 2 :(得分:-1)
您可以向StreamReader添加额外的方法(例如Mono的源代码可用于此目的):
private StringBuilder lineBuilder;
public int RegexBufferSize
{
set { lastRegexMatchedLength = value; }
get { return lastRegexMatchedLength; }
}
private int lastRegexMatchedLength = 0;
public virtual string ReadRegex(Regex regex)
{
if (base_stream == null)
throw new ObjectDisposedException("StreamReader", "Cannot read from a closed RegexStreamReader");
if (pos >= decoded_count && ReadBuffer() == 0)
return null; // EOF Reached
if (lineBuilder == null)
lineBuilder = new StringBuilder();
else
lineBuilder.Length = 0;
lineBuilder.Append(decoded_buffer, pos, decoded_count - pos);
int bytesRead = ReadBuffer();
bool dataTested = false;
while (bytesRead > 0)
{
var lineBuilderStartLen = lineBuilder.Length;
dataTested = false;
lineBuilder.Append(decoded_buffer, 0, bytesRead);
if (lineBuilder.Length >= lastRegexMatchedLength)
{
var currentBuf = lineBuilder.ToString();
var match = regex.Match(currentBuf, 0, currentBuf.Length);
if (match.Success)
{
var offset = match.Index + match.Length;
pos = 0;
decoded_count = lineBuilder.Length - offset;
ensureMinDecodedBufLen(decoded_count);
lineBuilder.CopyTo(offset, decoded_buffer, 0, decoded_count);
var matchedString = currentBuf.Substring(match.Index, match.Length);
return matchedString;
}
else
{
lastRegexMatchedLength *= (int) 1.1; // allow for more space before attempting to match
dataTested = true;
}
}
bytesRead = ReadBuffer();
}
// EOF reached
if (!dataTested)
{
var currentBuf = lineBuilder.ToString();
var match = regex.Match(currentBuf, 0, currentBuf.Length);
if (match.Success)
{
var offset = match.Index + match.Length;
pos = 0;
decoded_count = lineBuilder.Length - offset;
ensureMinDecodedBufLen(decoded_count);
lineBuilder.CopyTo(offset, decoded_buffer, 0, decoded_count);
var matchedString = currentBuf.Substring(match.Index, match.Length);
return matchedString;
}
}
pos = decoded_count;
return null;
}
在上述方法中,使用以下变量:
ReadBuffer()方法需要从流中读取数据。 方法ensureMinDecodedBufLen()需要确保decode_buffer足够大。
调用方法时,传递需要匹配的正则表达式。