优化的字符串插入算法

时间:2012-01-26 14:29:40

标签: ruby algorithm optimization jruby

我们的软件中有一小部分在大量代码(平均长度为900000个字符)的特定匹配字符串之前和之后插入字符串。

示例:

  

Lorem Ipsum只是打印和排版的虚拟文本   行业。 Lorem Ipsum一直是业界标准的虚拟文本   自16世纪以来,当一个未知的打印机采用了类型的厨房   把它拼凑成一本样本书。

替换为

Lorem Ipsum只是<span class="class1 class2">printing</span>和排版行业的虚拟文本。 Lorem Ipsum拥有<span class="class1 class2 class3">been</span>行业标准的虚拟文本<span class="class1">ever since the 1500s</span>,当一个未知的打印机拿出一个类型的厨房并加扰它制作一个类型的样本书。


好的,到目前为止一切顺利。我们可以只搜索和替换,但内容在某种程度上是语义相关的,因此在这种情况下printing被替换,但可能不在文本的其他位置。 我们所做的是索引,我们想要替换文本,因此对于每次替换,我们都会获得起始位置和结束位置。

当前代码:

new_val = huge_string_goes_here
entities.each { |entity|
    add_before = "<span class=\"#{entity.getStuff}\">"
    add_after = '</span>'

    new_val.insert(entity.getStart+increment, add_before)
    increment = increment+add_before.length
    new_val.insert(entity.getEnd+increment, add_after)
    increment = increment+add_after.length
}

分析900000个字符长的字符串大约需要15-20秒。

有没有人对如何优化它有任何建议?

谢谢

3 个答案:

答案 0 :(得分:2)

考虑编写一个可以找到匹配索引的C extension module for Ruby - 这种操作本身应该比解释代码快得多。获得索引后,可以使用Ruby来插入前/后文本,或者如果性能仍然需要提升,那么请考虑在C中完成所有操作。

请注意,与任何优化一样,关键是要确保您的“优化”实际上对非优化代码有所改进。为一些示例案例编写基准,并跟踪纯Ruby代码所花费的时间,然后使用您的原生扩展运行相同的基准测试,看看性能是否更好。

答案 1 :(得分:2)

如果您不想使用较低级别的语言来完成它,那么改变您的想法可能会有用,这样您就可以扫描源字符串一次并写出一个新字符串(如果可以的话)预先分配,更好),因为这将消除在插入点N后面移动所有~90万-N字符的需要。

还有一些特殊的表示可以很快地进行这些操作(例如ropes),但是你不应该为这种情况需要类似的东西。

编辑:由于巨大的常数因素被忽略和/或它们不能解释现代建筑,许多具有良好大Os的旧数据结构(以及那些具有良好大Os的新数据结构)在实践中都很慢。例如缓存,计算与检索)。绳索似乎太过指针密集而不能在实践中快速运行,并且你可以通过gap buffer之类的东西做更好的事情来进行常规缓冲编辑。

答案 2 :(得分:1)

我会使用foma来完成这类任务,但我不确定你能用它来整合语义。它与命令式思维不同,但一旦你知道这个想法,那个案子应该相当容易。 Foma是xfst的开源实现,因此您可以使用他们的资源。