【发布时间】:2012-07-17 04:13:36
【问题描述】:
我正在尝试在我正在开发的网站之一中完成搜索功能。由于我的搜索结果只显示匹配项内容的摘录,我想做的是突出显示搜索结果中的搜索词,并仅显示实际包含这些搜索词的部分文本。
我想我要做的是从数据库中获取全部内容并使用 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 的MATCH()...AGAINST() 在多个列上搜索MyISAM FULLTEXT indeces 的搜索词。但是,上述正则表达式仅应用于一列(我们称此列,即使用上述正则表达式的列,content)。
所以我的问题是,每当我在其他列而不是 content 列上得到匹配时,上面的正则表达式就会从 content 列中删除所有文本。这是因为一开始的 (?:.*?) 子模式会继续匹配,而不会找到下一个子模式。
我想知道是否有任何其他方法可以在没有这种副作用的情况下实现正则表达式的原始目的。我目前正在考虑简单地使用 preg_match_all 来匹配搜索词及其前后的 10 个单词。我将遍历所有匹配项并手动构建预览文本。是的,这是一个不错的解决方案,但考虑到我对正则表达式的缺乏经验,我想我不妨尝试找到一个解决方案。
更新
我刚刚注意到,当我输入 2 个或更多搜索词时,我只会得到空白 contents。除此之外,它完美无缺。我现在不知道为什么会这样。
更新 2
回显preg_last_error(),我收到此错误PREG_BACKTRACK_LIMIT_ERROR。我使用 new 和 post 作为搜索词。
正则表达式的var_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})
但我仍然愿意为更好的正则表达式提供建议。谢谢!
【问题讨论】:
-
当一个搜索词出现在另一个搜索词之后的 10 个单词内时怎么办?通过这种方法,您将不会包含其后的 10 个单词。这样可以吗?当搜索词真正频繁出现时怎么办?您是否同意这可能会返回整个文本?似乎您可能需要一种稍微昂贵的方法才能做好这件事......
-
preg_replace 是返回空字符串还是 null?如果它返回 null ,那么您的模式中有一个错误,在这种情况下,您可能想要回显它。第一个想法是您需要 preg_quote 这些值,除非您已经在构建数组的过程中将它们分解为字母数字字符。
-
嗨!我更新了问题以说明错误。我确实同意搜索词彼此太接近是一个问题。感谢那些cmets!我不介意它返回整个文本,因为我在回显之前截断了内容。
-
可能值得 print_r-ing 您的术语数组或呼应模式 - 可能是您以某种方式获得 '' 或 ' '
-
我使用
Regex Coach引导我完成匹配模式,它似乎在找不到(new|post)的匹配项后无限回溯。目标文本只是一个随机的 3 段 lorem ipsum。变量的var_dump在编辑的问题中
标签: php regex full-text-search preg-replace