2011-04-06 103 views
2

希望其中一位偉大的頭腦可以幫助我。PHP字符串評估方法

我有一種情況,我會從提供商那裏收到一個國際電話號碼,我必須做一個數據庫查找,並找出電話號碼正在呼叫的國家,地區和電話類型。

例如,假設我會收到一個電話號碼+393234567891。我必須在電話號碼所屬的國家的表格中查找。所以我知道'39'是意大利,我把它作爲數據庫中的國家代碼,但我必須確定這個號碼是固定電話還是手機。爲此我需要更多的電話號碼信息,所以'39'是固定電話,'393'是手機。我需要看到電話號碼包含'393',因此我知道這是一部手機。

我的問題是評估這個最好的方法是什麼?是不是要循環瀏覽電話號碼的每一部分,比如首先將前兩個電話號碼與數據庫進行比較,然後是前三個電話號碼,然後是前四個電話號碼,直到我返回一個單一結果?例如,如果我繼續這個例子,並將意大利的'39'與db進行比較,那麼我會返回一堆結果,因爲有'39'和'393'以及'3939'等等。那麼,使用整個電話號碼來獲取電話號碼前綴的完全匹配的最佳方式是什麼?

我原以爲只是通過電話號碼循環,並將一個數字的電話號碼添加到循環,直到我回來只有一個結果,我只是想確保這是最有效的方法來完成這個。

有什麼建議嗎?謝謝!

+0

您在詢問比較數據,但不是關於獲取國家和地區代碼數據的更正? – 2011-04-06 09:51:13

回答

2

我假設你有一個表,如:

prefix (id, number) 

與像數據:

1, '39' 
2, '393' 
3, '33' 
4, '331' 

您可以用反向得到最長匹配LIKE

SELECT id 
FROM prefix 
WHERE "393234567891" LIKE CONCAT(number, "%") 
ORDER BY LENGTH(number) 
LIMIT 1; 

我還沒有測試過,但假設你最短的前綴是2個字符,你可能會得到一些改善(這隻會檢查前綴開頭39,這是所有前綴的1%,你有):

SELECT id 
FROM prefix 
WHERE "393234567891" LIKE CONCAT(number, "%") 
    AND number LIKE "39%" 
ORDER BY LENGTH(number) 
LIMIT 1; 

然後你就可以有不同的表與,情報附加到前綴,如:

prefixinfo (id, prefix_id, type, data) 

與像數據:

1, 1, 'country', 'Italy' 
2, 2, 'country', 'Italy' 
3, 2, 'type', 'Landline' 
4, 3, 'country', 'France' 
5, 4, 'country', 'France' 
6, 4, 'city', 'Paris' 
+0

是的 - 這是我如何解決問題 - 注意在上面的代碼中有一個BUG - 'ORDER BY number.length'應該是'ORDER BY LENGTH(number) DESC',您可以將該類型添加到前綴表(數字,國家,類型)並通過單個操作獲取結果。 – symcbean 2011-04-06 12:31:09

+0

@symcbean Thnaks,改正!但是我不能將信息塊添加到前綴中,因爲它們之間存在一對多的關係。由於查詢只會返回'393'的ID(因爲這是最具體的),所有信息必須從該記錄開始可用。 - 由於'LIKE'是最昂貴的操作,我寧願不使用所有適用的前綴,但僅限於最具體的前綴。 – vbence 2011-04-06 14:31:41

+0

我只是不明白爲什麼你將'country'和'type'分隔成2行prefix_id = 2。否則我喜歡這個解決方案。 – Slava 2011-04-06 14:58:50

0

如果實際的電話號碼是固定大小,您可以將其刪除。與sub_strreplace;例如數字是8位長:

$code = substr_replace($number,'',-1,8); 

$ code現在將只包含代碼部分。所以你可以很容易地計算數字,並找出你需要什麼。

+0

這不會有幫助,因爲他有許多不同長度的前綴(如「39」和「393」和「3939」)。他需要比較數字與*最長的匹配前綴* – 2011-04-06 09:56:05

0

最後3,其表示一個移動在393年,每個國家都一樣嗎?

理想的情況是有國家的一個表,然後另一個表相關的前綴

Countries table      Subsearch Table 

countryMatch: 39      substrMatch: 3 // for 393    
countryName: "Italy"     substrCountry: 39 
             substrMeaning: "cell" 
             ................... 
             substrMatch: 5 // 395 
             substrCountry: 39 
             substrMeaning: "something else" 

這樣,一旦你已經確定的國家可以限制你的搜索,其餘爲進一步限制例如393,3939.

我認爲你提出的方法是合理的,循環一點點,直到你找到使用SQL查詢的匹配。因此,通過彈出前兩位數字(39)找到國家代碼,如果發現查詢結果的子搜索表。通過這些附加到國家代碼,看看你得到一個匹配

$subsearchArr = array("3" => "cell","5" => "something else") # from the database 
$match = false; 
$country = 39; 

foreach($subsearchArr as $key => $value) 
{ 
    # append $key to $country e.g. 393, 395 
    # if this is a match to the string 
    # set match to true and do your logic 
} 

if($match == false) # no match so landline 
{ 
    # logic here if landline 
} 

這些結果循環我認爲,將工作,但我想我不得不看到確切的數據結構,以確保萬無一失。但是,兩個表格絕對是可取的

-1

即使您在Mysql中有數據,使用簡單的數組循環進行PHP比較也許會更好。從數據庫(和緩存)建立一個預期國家代碼和已知的唯一前綴在每個國家的PHP陣列,以區分移動,固定電話,地區等。

對於您所擁有的每個國家/地區代碼,請查看輸入的電話號碼是否開始與該代碼。找到國家後,從電話號碼中刪除國家/地區代碼,並根據該國家已知移動號碼前綴列表測試剩餘號碼。如果找到,它是移動的。如果沒有找到,它是固定電話。

例如,在希臘,國家代碼是30,所有手機都以69開頭。但是,如果您正在與移動號碼前綴與地區代碼(如美國和加拿大)無法區分的國家/地區進行溝通,那麼您運氣不好。

function checkMSISDN($msisdn) { 

    $countries = array(
     'gr' => array(
      'countryPrefix' => '30', 
      'mobilePrefix' => '3069', 
      'length' => 12, 
     ), 
     'it' => array(
      'countryPrefix' => '39', 
      'mobilePrefix' => '393', 
      'length' => 12, 
     ), 
    ) ; 

    foreach ($countries as $countryName => $countryRules) { 

     $msisdnCurrent = $msisdn ; 

     $countryPrefix = $countryRules['countryPrefix'] ; 
     $fullPrefix = $countryRules['mobilePrefix'] ; 

     //remove leading + if any 
     if (substr($msisdnCurrent, 0, 1) == '+') { 
      $msisdnCurrent = substr($msisdnCurrent, 1) ; 
     } 

     //remove leading 00 if any 
     if (substr($msisdnCurrent, 0, 2) == '00') { 
      $msisdnCurrent = substr($msisdnCurrent, 2) ; 
     } 

     $msisdnLength = strlen($msisdnCurrent) ; 
     if ($msisdnLength != $countryRules['length']) { 
      //sanity check, not this country 
      continue ; 
     } 

     if (substr($msisdnCurrent, 0, strlen($countryPrefix)) != $countryPrefix) { 
      //not this country 
      continue ; 
     } 

     if (substr($msisdnCurrent, 0, strlen($fullPrefix)) != $fullPrefix) { 
      //not mobile 
      return "isLandline" ; 
     } 
     else { 
      //mobile 
      return "isMobile" ; 
     } 
    } 
    return false ; 
} 
+0

你應該讓數據庫去做。如果腳本能夠很好地處理大量數據庫,那麼就不會實現如此複雜的查詢語言。 – Slava 2011-04-06 14:55:45

+0

@Slava我並不普遍反對。然而,在這種情況下,確定MSISDN所處的國家和移動電話號碼的規則是一個小數據集,而您的輸入量很大(需要檢查多個MSISDN)。將規則存儲在數據庫中以便更好地管理,但將其緩存到PHP中並在內存中執行處理。然後它只是簡單的子串比較,甚至沒有子串搜索。 PHP非常棒。使用子字符串搜索命中數據庫會變得很快。 – Fanis 2011-04-06 17:46:49