首页 > 解决方案 > 在 perl 中替换文本中的一组单词的速度 -

问题描述

上下文优先:我试图在维基百科页面中突出显示歌曲标题。首先,我从页面中获取引用的部分,检查它们是否存在于歌曲标题数据库中,然后突出显示我找到的那些。数据库部分速度惊人,提取歌曲标题(引用它们)也是如此。

因此(我认为)我需要替换 HTML 中的一组单词(标题)并将它们包装在这样的跨度中(对于每个单词):

s/word/<span class="something">word<\/span>/gi

文本长约 100k,列表约 300 个单词(均未预先确定),因此一次替换一个单词的迭代过程太慢(如果可能,我需要将其保持在 < 1 秒)。

所以我已经完成了

my $re = join '|', map { quotemeta($_) } @words;
$dom =~ s/($re)/<span class="something">$1<\/span>/gi;

这似乎有效并且速度很快(在我的基准案例中为 0.64)。

现在我想替换\"$word\"而不是只是$word这样我尝试了这个:

my $re = join '|', map { quotemeta(join '', '"', $_, '"') } @words;

速度下降了 10 倍。将速度与 NYTProf 进行比较,所有差异似乎都在内部CORE:substcont

这是为什么?

(非常感谢有关如何避免替换标签内的文本的建议,例如id="word_to_be_replaced"

标签: perl

解决方案


我不知道您实际上在做什么,因为您只提出了您认为问题所在的内容(而我们看不到其余的内容)。

首先,你有join '', '"', $_, '"',但这只是qq("$_")

接下来,如果你有一个被引号包围的单词,你不需要在每个单词周围加上引号。将单词更改分组并在其周围加上引号:

s/ " (?: word1 | word2 | ... ) " /.../x;

我的第一个怀疑是,无论您的模式做什么,都涉及更多的回溯。

为了避免替换 HTML 中可能存在的相同文本,我会使用 HTML 解析器并且只查看文本。但是,这将比已经发生的事情花费更长的时间。


推荐阅读