2011-04-06 99 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