2012-07-01 92 views
2

我想製作一個產品搜索引擎,用戶輸入產品代碼並將結果返回,這很容易。使用正則表達式替換搜索MySQL數據庫

但是,我希望能夠補償看起來像字母的數字,反之亦然。

E.g用戶類型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] 1] BC 而不是[線1l] BC

回答

1

,你有帶字母的產品代碼?在運行查詢之前,您可以將查詢字符串轉換爲所有數字。這是最容易做的事情,並且比測試兩者都快得多。

+0

嗨,產品代碼可以有字母和數字的混合(和符號像 - 但沒關係)。 – imperium2335

+0

@ juergen_d的回答是明智的。你可以通過執行'WHERE code LIKE'6%'和代碼REGEXP'6 [o0] 12 [1l]''來加速它。這樣,可以在字母/數字組合前的前綴上使用索引。否則,它會每次在所有6M行上運行正則表達式。 –

+0

+1首字母的想法,這對我來說加快了很多 – imperium2335

1

使用此:

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

爲什麼向下票呢?這將做最初的要求。 – Andy

+0

如何將用戶變量帶入查詢中?即$查詢= $ _POST ['搜索字符串'] – imperium2335

1

您無法使用正則表達式高效地搜索數據庫。但是,您可以將數據轉換爲標準化形式的存儲空間,然後使用標準化查詢字符串進行搜索,例如所有O的零,Il的一個等等。

+0

雖然我的數據庫中有大約600萬種產品。如果我爲1-ls和0-os創建變體,它會顯着增加我的數據庫的大小:/ – imperium2335

+0

@ imperium2335:我建議你規範化所有文本,而不是創建每個條目的許多變體。你不能在6M行上運行正則表達式。 – MaxSem

0

我解決了它: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); 
} 
0

另一種選擇

// 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 
       ") ; 
相關問題