【问题标题】:Search MySQL database with regex substitutions使用正则表达式替换搜索 MySQL 数据库
【发布时间】:2012-07-02 05:26:50
【问题描述】:

我想做一个产品搜索引擎,用户输入产品代码,它会返回结果,这很容易。

但是,我希望能够补偿看起来像字母的数字,反之亦然。

例如用户输入6O12l,但产品代码实际上是60121。

我需要在 SQL 查询中输入什么来恢复所有具有 6O12l 和/或 60121 的产品?


到目前为止,我有这个不起作用,无论我输入什么,它每次都会返回相同的结果:

$searchString = $_POST['query'] ;
$searchString = preg_replace('#\W#', '', $searchString);

$firstLetter = substr($searchString, 0, 1) ;

include("db.php") ;

$result = $dbh->prepare("SELECT productCode
                     FROM products
                     WHERE productCodeREGEXP '6[O0]12[1l]'
                     AND productCode LIKE '$firstLetter%'") ;
$result->execute() ;

while($row = $result->fetch(PDO::FETCH_ASSOC)) {
echo $row['productCode'].'<br />' ;
}

我已经设法让它工作了,但我遇到了一个新问题。

我正在使用 str_replace 将用户查询字符串中的数字替换为字母,反之亦然,但它只适用于其中之一,而不适用于两者:

$qString = str_replace(array('o', 'l', '0', '1'), array('[O0]', '[1l]', '[O0]', '[1l]'), $searchString) ;

这给了我一个错误的输出,例如A[[1l]l]BC 而不是 A[1l]BC

【问题讨论】:

    标签: php mysql regex search


    【解决方案1】:

    你们有带字母的产品代码吗?您可以在运行查询之前将查询字符串转换为所有数字。这是最容易做的事情,而且比测试两者都要快得多。

    【讨论】:

    • 您好,产品代码可以混合使用字母和数字(以及类似符号 - 但没关系)。
    • @juergen_d 的回答是明智的。您可以通过 WHERE code LIKE '6%' AND code REGEXP '6[o0]12[1l]' 加快速度。这样,可以在字母/数字组合之前的前缀上使用索引。否则,它每次都会在所有 6M 行上运行正则表达式。
    • +1 表示第一个字母的想法,这对我来说加快了很多速度
    • 您应该尽可能多地使用查询字符串,直到第一个 '[O0]' 模式。
    【解决方案2】:

    您无法使用正则表达式有效地搜索数据库。但是,您可以将数据转换为规范化形式进行存储,并使用规范化查询字符串进行搜索,例如所有O 都归零,Il 归零等等。

    【讨论】:

    • 我的数据库中有大约 600 万种产品。如果我为 1-ls 和 0-os 创建变体,它将显着增加我的数据库的大小:/
    • @imperium2335:我建议您对所有文本进行规范化,而不是为每个条目创建大量变体。您不能在 6M 行上运行正则表达式。
    【解决方案3】:

    使用这个:

    SELECT * from products
    where code REGEXP '6[O0]12[1l]'
    

    【讨论】:

    • 如何将用户变量带入查询?即 $query = $_POST['searchstring']
    【解决方案4】:

    我解决了:D

    作为参考,我在 PHP.net 上找到了这个函数:

    function search_replace($s,$r,$sql)
    { $e = '/('.implode('|',array_map('preg_quote', $s)).')/';
    $r = array_combine($s,$r);
    return preg_replace_callback($e, function($v) use ($s,$r) { return $r[$v[1]]; },$sql);
    } 
    

    【讨论】:

      【解决方案5】:

      另一种选择

      // regex expresssion 
      // str_replace goes in order, first change letters to numbers, then change to the regex
      // 6012ol becomes 6[0O][1l]2[0O][1l]
      $regexString = str_replace(array('o', 'l', '0', '1'), array('0', '1', '[0O]', '[1l]'), $searchString);
      
      // like expression, allows the database to make the initial filter, _ is the single character match
      // 6012ol becomes 6__2__
      $likeString = str_replace(array('o', 'l', '0', '1'), '_'), $searchString);
      
      $filt1 = "(productCode LIKE '$likeString%')"; // last % allows for partial matches
      $filt2 = "(productCode REGEXP '$regexString')";
      
      // now query, with the like filter first
      $dbh->prepare("SELECT productCode
                            FROM products
                            WHERE $filt1 AND $filt2
                    ") ;
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-04-20
        • 1970-01-01
        • 2019-11-03
        • 2013-06-14
        • 1970-01-01
        • 1970-01-01
        • 2015-11-06
        相关资源
        最近更新 更多