我正在尝试在我正在开发的网站之一中完成搜索功能。由于我的搜索结果只显示匹配项目内容的摘录,我想做的是突出显示搜索结果中的搜索词,并只显示实际包含这些搜索词的部分文本。
我想我要做的是从数据库中获取全部内容并使用在搜索词周围preg_replace
插入<span>
元素,同时只提取词前后的前 10 个词。所以这是它的正则表达式部分:
(?:.*?)((?:\w+\W+){0,10})('.implode('|', $terms).')((?:\W*\w+\W+){0,10})
基本上,我尝试使用非捕获子模式“丢弃”除搜索词之前的前 10 个单词之外的所有文本,然后获取该词之前的 10 个词,然后是词本身,然后是接下来的 10 个词。
这是中的替换文本preg_replace
:
\\1<span class="search-term search-term-content">\\2</span>\\3...
MySQL
正在通过'sMATCH()...AGAINST()
搜索搜索词以查找MyISAM FULLTEXT
多列上的索引。但是,上述正则表达式仅应用于一列(我们称此列,即使用上述正则表达式的列content
)。
所以我的问题是,每当我在其他列而不是列上得到匹配时content
,上面的正则表达式就会从content
列中删除所有文本。这是因为一(?:.*?)
开始的子模式会继续匹配,而不会找到下一个子模式。
我想知道是否有任何其他方法可以在没有这种副作用的情况下实现正则表达式的原始目的。我目前正在考虑简单地使用preg_match_all
来匹配搜索词及其前后的 10 个单词。我将遍历所有匹配项并手动构建预览文本。是的,这是一个不错的解决方案,但考虑到我对正则表达式的经验不足,我想我不妨尝试找到解决方案。
更新
我只是注意到,contents
当我输入 2 个或更多搜索词时,我只会变得空白。除此之外,它完美无缺。我现在不知道为什么会这样。
更新 2
回声preg_last_error()
,我得到这个错误PREG_BACKTRACK_LIMIT_ERROR
。我使用这些词new
和post
作为搜索词。
正则表达式的Avar_dump
和术语显示了这一点:
@(?:.*?)((?:\w+\W+){0,10})(new|post)((?:\W*\w+\W+){0,10})@i
array
0 => string 'new' (length=3)
1 => string 'post' (length=4)
更新 3
我曾经Regex Coach
引导我完成匹配模式,似乎它在找不到匹配后回溯太多(new|post)
。目标文本只是一个随机的 3 段 lorem ipsum。我想我需要为这项任务找到一个更好的正则表达式。
更新 4
使用Once-Only
子模式可以解决问题。虽然我不知道它的细节,但我只是重新阅读了 PHP 手册并阅读了其中的一部分,Once-Only
子模式有助于过多的回溯。这是新的正则表达式:
(?:.*?)((?>\w+\W+){0,10})('.implode('|', $terms).')((?:\W*\w+\W+){0,10})
但我仍然愿意为更好的正则表达式提供建议。谢谢!