让我们假设有一个文本流(或 Java 中的 Reader),我想检查一个特定的字符串。文本流可能非常大,所以一旦找到搜索字符串,我想返回 true 并尽量避免将整个输入存储在内存中。
天真地,我可能会尝试做这样的事情(在 Java 中):
public boolean streamContainsString(Reader reader, String searchString) throws IOException {
char[] buffer = new char[1024];
int numCharsRead;
while((numCharsRead = reader.read(buffer)) > 0) {
if ((new String(buffer, 0, numCharsRead)).indexOf(searchString) >= 0)
return true;
}
return false;
}
当然,如果给定的搜索字符串出现在 1k 缓冲区的边界上,则无法检测到它:
搜索文本:“计算器”
流缓冲区 1:“abc …….stack”
流缓冲区 2:“溢出…….xyz”
我如何修改这段代码,以便它在缓冲区边界正确地找到给定的搜索字符串,而不会将整个流加载到内存中?
编辑: 请注意,当在流中搜索字符串时,我们试图 尽量减少从流中读取的次数(以避免网络/磁盘中的延迟)并 保持内存使用不变,而不管流中的数据量如何。 字符串匹配算法 的实际效率是次要的,但显然,找到一种使用这些算法中效率更高的算法的解决方案会很好。
原文由 Alex Spurling 发布,翻译遵循 CC BY-SA 4.0 许可协议
我对部分搜索的 Knuth Morris Pratt 算法做了一些更改。由于实际的比较位置总是小于或等于下一个,因此不需要额外的内存。带有 Makefile 的代码也可以在 github 上找到,它是用 Haxe 编写的,可以同时针对多种编程语言,包括 Java。
我还写了一篇相关的文章: searching for substrings in streams: a small modification of the Knuth-Morris-Pratt algorithm in Haxe 。这篇文章提到了 Jakarta RegExp ,现在已经退休并在 Apache Attic 中休息。 RE 类中的 Jakarta Regexp 库“ match ”方法使用 CharacterIterator 作为参数。