【问题标题】:In PHP, get entire word from MySQL search result using "LIKE"在 PHP 中,使用“LIKE”从 MySQL 搜索结果中获取整个单词
【发布时间】:2013-04-10 15:24:55
【问题描述】:

我想要的是: 假设我使用如下查询搜索“goo”:...WHERE message LIKE '%goo%',它返回给我一个结果,例如I love Google to make my searches, but I'm starting to worry about privacy,所以它将显示为结果,因为单词Google 符合我的搜索条件.

如何根据我的搜索字符串将整个 Google 结果保存在变量中? 我需要这个,因为我正在使用一个正则表达式,它将突出显示搜索的单词并在此结果之前和之后显示内容,但它仅在搜索的单词与结果中的单词完全匹配时才有效,而且它的结构错误,所以它赢了不适用于没有被空格包围的单词。

这是正则表达式代码

<?=preg_replace('/^.*?\s(.{0,'.$size.'})(\b'.$_GET['s'].'\b)(.{0,'.$size.'})\s.*?$/',
            '...$1<strong>$2</strong>$3...',$message);?>

我想要的是将此 $_GET['s'] 更改为我的变量,该变量将包含在我的查询字符串中找到的整个单词。

我如何做到这一点?

【问题讨论】:

  • 关于\B* 不起作用(我已阅读您的讨论),这很正常。 \B(就像\b)匹配位置(不是单词边界)。你可以重复一个字符,但重复一个位置是没有意义的。

标签: php mysql regex search


【解决方案1】:

我阅读了your discussion on this 并且可能需要更健壮的实现。特别是考虑到您需要支持diacritics。使用单个正则表达式来解决所有问题可能看起来很诱人,但它越复杂就越难以维护或扩展。引用Jamie Zawinski

有些人在遇到问题时会想“我知道,我会使用正则表达式”。现在他们有两个问题。

由于我在本地机器上使用iconv 有问题,所以我使用了更简单的实现,如果您的情况需要,请随时使用something more complicated or robust

我在这个解决方案中使用了一个简单的正则表达式来仅获取一组字母数字字符(也称为“单词”),正则表达式中读取\p{L}\p{M} 的部分确保我们也get all the multibyte characters

你可以看到this code working on IDEone

<?php
function stripAccents($p_sSubject) {
    $sSubject = (string) $p_sSubject;

    $sSubject = str_replace('æ', 'ae', $sSubject);
    $sSubject = str_replace('Æ', 'AE', $sSubject);

    $sSubject = strtr(
          utf8_decode($sSubject)
        , utf8_decode('àáâãäåçèéêëìíîïñòóôõöøùúûüýÿÀÁÂÃÄÅÇÈÉÊËÌÍÎÏÑÒÓÔÕÖØÙÚÛÜÝ')
        , 'aaaaaaceeeeiiiinoooooouuuuyyAAAAAACEEEEIIIINOOOOOOUUUUY'
    );


    return $sSubject;
}

function emphasiseWord($p_sSubject, $p_sSearchTerm){

    $aSubjects = preg_split('#([^a-z0-9\p{L}\p{M}]+)#iu', $p_sSubject, null, PREG_SPLIT_DELIM_CAPTURE);

    foreach($aSubjects as $t_iKey => $t_sSubject){
        $sSubject = stripAccents($t_sSubject);
        
        if(stripos($sSubject, $p_sSearchTerm) !== false || mb_stripos($t_sSubject, $p_sSearchTerm) !== false){
            $aSubjects[$t_iKey] = '<strong>' . $t_sSubject . '</strong>';
        }
    }

    $sSubject = implode('', $aSubjects);
    
    return $sSubject;
}


/////////////////////////////// Test \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
$aTest = array(
      'goo' => 'I love Google to make my searches, but I`m starting to worry about privacy.'
    , 'peo' => 'people, People, PEOPLE, peOple, people!, people., people?, "people, people" péo'
    , 'péo' => 'people, People, PEOPLE, peOple, people!, people., people?, "people, people" péo'
    , 'gen' => '"gente", "inteligente", "VAGENS", and "Gente" ...vocês da física que passam o dia protegendo...'
    , 'voce' => '...vocês da física que passam o dia protegendo...'
    , 'o' => 'Characters like æ,ø,å,Æ,Ø and Å are used in Denmark, Sweden and Norway'
    , 'ø' => 'Characters like æ,ø,å,Æ,Ø and Å are used in Denmark, Sweden and Norway'
    , 'ae' => 'Characters like æ,ø,å,Æ,Ø and Å are used in Denmark, Sweden and Norway'
    , 'Æ' => 'Characters like æ,ø,å,Æ,Ø and Å are used in Denmark, Sweden and Norway'
);

$sContent = '<dl>';
foreach($aTest as $t_sSearchTerm => $t_sSubject){
    $sContent .= '<dt>' . $t_sSearchTerm . '</dt><dd>' . emphasiseWord($t_sSubject, $t_sSearchTerm) .'</dd>';
}
$sContent .= '</dl>';

echo $sContent;
?>

【讨论】:

  • 您使用的 utf_decode 方法不包括丹麦、瑞典和挪威使用的 æøåÆØÅ。这难道不是一个潜在的问题吗?
  • @melwil 是的,这将证明是一个问题,因此我建议读者在情况需要时使用更复杂或更强大的实现。如果您有一个稳定的开发环境(即镜像您的生产服务器的环境),您可以使用iconv 来翻译字符。否则你需要adjust the code to your situation。为了它的乐趣(并给你一个更准确的例子)我已经更新了我的答案以包括你提到的字符。
【解决方案2】:

我不明白匹配搜索字符串中其他所有内容的重要性,这还不够吗?

<?=preg_replace('/\b\S*'.$GET['s'].'\S*\b/i', '<strong>$0</strong>', $message);?>

据我所知,您只是将匹配的单词放在 html 标记中,而对字符串的其余部分没有做任何事情?

上述正则表达式适用于您只匹配整个单词、捕获字符串中的多个匹配项(应该有多个匹配项)以及不区分大小写的情况。

【讨论】:

  • 我认为换行括号没那么有用(如果我没记错的话,你可以在 PHP 中使用$0)。但是,是的,这似乎是最简单的解决方案。
  • @Loamhoof 是的,你是对的。这只是我简化后的残余。
【解决方案3】:

我敢打赌,更改正则表达式以检查包含该术语的任何单词会更容易,那么:

<?=preg_replace('/^.*?(.{0,'.$size.'})(\b\S*'.$_GET['s'].'\S*\b)(.{0,'.$size.'}).*?$/i',
            '...$1<strong>$2</strong>$3...',$message);?>

【讨论】:

  • 我认为要使其按预期工作,我不仅要检查包含该术语的任何单词,还要在 REGEX 中模拟所有 MySQL LIKE 功能(不区分大小写、特殊字符等),我不'认为我不能做到这一点,那会怎样?
  • 我更改了表达式添加 /i 修饰符以使其不区分大小写并将 \w* 替换为 .* 以匹配任何字符,我认为这应该(几乎)有效。
  • 事情变得更糟了 :( 现在,在某些结果中,它在匹配的单词之前和之后将很多单词包装成强标签,而在其他结果中,它不会包装任何东西
  • 上一次编辑再试一次,我用那些问号 (.*?) 做了很多懒惰。希望这次真的有效:)
  • 让我们再次尝试取除空格以外的所有内容...:S
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-10-02
  • 2018-04-29
  • 1970-01-01
  • 2021-03-31
相关资源
最近更新 更多