【问题标题】:PHP Search Results displayPHP 搜索结果显示
【发布时间】:2014-10-08 14:34:13
【问题描述】:

我正在为我的框架创建一个基本的搜索功能,并寻找一些关于如何以最佳方式(谷歌风格)显示搜索结果的建议。我的 MYSQL 查询根据搜索查询返回不同的页面。从 MySQL 返回的结果是完美的,我只需要执行以下操作:

例如,有人搜索“Hello World”一词。我的搜索结果将返回包含“hello”和“world”的所有行。

我想要实现的是:

  • 突出显示搜索查询中的单词,但仅突出显示结果的一部分。我只想返回 200 个字符并突出显示(粗体)搜索词中任何单词的第一次出现。
  • 显示的副本将在 CMS 中创建并具有 html 标记。我可以在显示之前去除 html 标签,但如果我以正确的方式进行操作,我希望获得反馈。

我目前使用的代码是:

  // The query string:
  <?php $q = urldecode($_GET['qString']); ?>

  // Run a loop through the results:
  <?php foreach ($this->get("pageResults") AS $result): ?>
      // a clickable H3 to the actual page:
      <h3><?= $this->html->link($result['sub_heading'] . " " . $result['heading'], array("controller" => "pages", "action" => "viewer", "properties" => array($result['name']))) ?></h3>
      <?php
      // Strip all html characters as the content comes from an WYSIWYG editor:
      $value = preg_replace('/<[^>]*>/', '', $result['content']);
      // Find the position within the text:
      $position = stripos($value, $q);
      // If a positive position, display 200 characters and start -100 from the first occurance
      if ($position == true) {
           $string = substr($value, $position - 100, 200);
      } else {
           $string = " ... ";
      ?>
      <p><?= $string ?></p>
      <hr />
 <?php endforeach; ?>

我在这里遇到的主要问题是:

  1. 即使查询字符串,搜索结果也会返回行 不精确(因此如果该列包含 "hello" 和 "world" 而stripos 只会找到 "hello world"。
  2. 我不知道将&lt;strong&gt;&lt;/strong&gt; 标签包裹在剥离的html 中第一次出现的单词或短语周围的最佳方式。我知道这可能是一件棘手的事情,尤其是由于发生问题。没有这个功能我也可以活下去,但如果有一种很好的方法,那就太好了:)

任何想法将不胜感激!

【问题讨论】:

    标签: php html search


    【解决方案1】:

    我建议你阅读一下Natural Language Full-Text Searches

    这是执行搜索功能时最优化的方式(基于我的观点)。

    【讨论】:

    • 意识到您没有足够的代表发表评论,但这样的答案可能应该是评论。
    【解决方案2】:

    即使查询字符串不精确,搜索结果也会返回行(因此如果列包含“hello”和“world”,它将返回结果,而 stripos 只会找到“hello world”。

    这似乎是一个简单的答案,但看到您正在通过 url 传递查询字符串,我认为它看起来像这样:

    ?searchText=Hello%20World
    

    所以你可以打破空格上的单词(使用explode)并创建一个位置数组:

    $positionArray = array();
    
    $qs = explode($q, '%20');
    
    $value = preg_replace('/<[^>]*>/', '', $result['content']);
    
    foreach( $qs as $qword ){
        $position = stripos($value, $qword);
        array_push($positionArray, $position);
    }
    

    因此,现在您的单词出现在结果中的位置数组:

    positionArray = [4, 15, 32];
    

    因此,您可以在这些位置开始相关的突出显示标记(strong 或您正在使用的任何内容),然后在单词末尾关闭它们,或者您可以找到开始位置和结尾使用类似这样的词的位置:

    foreach( $qs as $qword ){
        $start_position = stripos($value, $qword);
        $end_position = $start_position + strlen($qword);
        array_push($positionArray, {qword: $qword, start_position:$start_position, end_position:$end_position});
    }
    

    不幸的是,我现在没有时间考虑如何在这些位置插入标签,我相信你会弄明白的(但你可以使用类似substr_replace 的东西)。无论如何,我希望这能给你一些想法。

    【讨论】:

      【解决方案3】:

      这是实现您所要求的一种相当简单的方法。

      首先,您没有说明您对搜索输入执行了哪些转换,但我猜您正在拆分单词并进行不区分大小写的搜索。因此,我将创建一个包含原始搜索字符串和已解析版本的数据结构,其中单词被拆分并小写:

      // $input is your sanitised query
      $arr = explode(" ", strtolower($input));
      
      $search_arr = [
          'original' => $input,
          'parsed' => $arr
      ];
      

      现在,处理来自数据库的结果:让我们调用$text 来自数据库的结果。

      # strip the html tags
      $stripped = strip_tags($text);
      
      # first, see if the original search query is in the page
      $pos = stripos($stripped, $search_arr['original']);
      if ($pos !== false) {
          # if it is, take a 200 character snippet of the page (note that
          # if the search string occurs earlier than the first 50 characters,
          # we just take the first 200 characters of the page [I used 50 rather
          # than 100 as 100 seemed too many]):
          if ($pos < 50) {
              $stripped = substr($stripped, 0, 200);
          }
          else {
              $stripped = substr($stripped, $pos-50, 200);
          }
          # use a regular expression to enclose the search string in a <strong> tag
          $stripped = preg_replace("/{$search_arr['original']}/i","<strong>$1</strong>", $stripped);
      }
      else {
          # otherwise, for each word in the parsed version of the search query...
          foreach ($search_arr['parsed'] as $s) {
              # surround it with <> and </> (I'm doing this in case part of the query
              # matches within the <strong> tag - of course, if <> and </> appear in
              # the source text, this could be a problem!) 
              $stripped = preg_replace("/($s)/i", "<>$1</>", $stripped);
          }
          # now replace the <> and </> with strong tags
          $find = [ '<>', '</>'];
          $replace = ['<strong>', '</strong>'];
      
          $stripped = str_replace($find, $replace, $stripped);
      
          # find the first <strong> tag...
          $pos = strpos($stripped, "<strong>");
          if ($pos < 50) {
              $stripped = substr($stripped, 0, 200);
          }
          else {
              $stripped = substr($stripped, $pos-50, 200);
          }
      }
      
      echo $stripped; 
      

      这是相当粗略的,您可能想改进一些东西,但它应该让您知道如何进行。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-06-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-03-27
        • 1970-01-01
        • 1970-01-01
        • 2021-01-25
        相关资源
        最近更新 更多