代码之家  ›  专栏  ›  技术社区  ›  nWorx

查找电话号码-查找带有或不带有电话分机的号码

  •  4
  • nWorx  · 技术社区  · 14 年前

    我有一张桌子,上面有大约13万张有电话号码的唱片。数字的格式都是这样的+4311234567。号码通常包括国际国家代码、本地区号、电话号码,有时还包括分机号码。

    有一个webservice检查表中调用方的号码。那项服务已经起作用了。但现在客户也希望,如果有人从一家公司打电话,该公司的号码已经在数据库中,但不是他的分机,该服务将返回一些结果。

    例如桌子。

       **id** | **telephonenumber**    | **name**   
    |    1    | +431234567             | company A  
    |    2    | +431234567890          |  employee in company A  
    |    3    | +4398765432            | company b 
    

    现在如果A公司的某个人用不同的分机打电话,例如+43123456777,那么它应该返回ID1。但问题是,我不知道分机有多少位。它可以有3,4或更多的数字。

    有没有串式匹配的模式?

    数据存储在sql2005数据库中。

    谢谢

    编辑:
    我从客户关系管理系统得到的电话号码。我已经和CRM的管理员谈过了,他正试图以不同的格式将数据发送给我。

       **id** | **telephonenumber** |**extension**   | **name**   
    |    1    | +431234567          |                | company A  
    |    2    | +431234567          |      890       |  employee in company A  
    |    3    | +4398765432         |                | company b 
    
    7 回复  |  直到 10 年前
        1
  •  2
  •   Community Jaime Torres    7 年前

    假设每个公司的分机号码可以不同 数字中的位数可能因国家和地区代码而异,这是一个需要有效解决的棘手问题。

    即使将数据表拆分为基数和扩展名,也必须将传入的数字拆分为基数和扩展名,我认为这会使事情复杂化。

    我想尝试的是:

    原始格式

    1. 尝试将传入的号码与数据库匹配。
      • 如果它符合一个记录,你有你的答案-一个特定的人。
      • 如果它与多个记录匹配,就会出现问题,所以失败。
      • 否则,你必须找到公司:
    2. 从传入的号码中去掉尾随数字,并再次尝试将其与数据库匹配。
      • 如果位数低于阈值(可能是6位数),则搜索可能会失败。这只是为了限制在找不到数据库搜索数时执行的数据库搜索数。
      • 如果没有匹配的记录,则需要再次尝试此步骤。
      • 如果它与多个记录匹配,就会出现问题,所以失败。
      • 如果它正好符合一个记录,你就有了下一个最好的答案——公司。

    例如,搜索“+43123456777”:

    • +43123456777匹配0个条目。
    • +4312345677匹配0个条目。
    • +431234567匹配1个条目:“公司A”

    这种方法的主要失败模式是如果一个公司有可变长度的扩展号。例如,如果431234567890和43123456789都是有效数字,但只有第二个数字在数据库中,会发生什么情况。如果输入的号码是431234567890,则43123456789将错误匹配。

    拆分格式

    这有点复杂,但更健壮。

    1. 尝试将传入的号码与数据库匹配。
      • 如果它符合一个记录,你就有你的答案-公司。
      • 如果它与多个记录匹配,则匹配不带扩展名的条目,即已找到公司。
      • 否则,您必须找到基本公司编号和扩展名:
    2. 从传入的号码中去掉尾随数字,并再次尝试将其与数据库匹配。
      • 如果位数低于阈值(可能是6位数),则搜索可能会失败。这只是为了限制在找不到数据库搜索数时执行的数据库搜索数。
      • 如果没有匹配的记录,则需要再次尝试此步骤。
      • 如果它符合一个记录,那么你找到了你的答案-公司。
      • 如果它与多个记录匹配,则您已找到公司的基号,因此现在知道扩展名,因此可以尝试查找特定人员:
    3. 从原始传入号码的开头去掉基号码,并使用此项搜索具有该基号码的记录的扩展名。
      • 如果它与一条记录完全匹配,那么您已经找到了一个特定的人。
      • 如果与某个特定的人不匹配,则匹配不带扩展名的条目,您就找到了公司。

    例如,搜索“+43123456777”:

    • +43123456777匹配0个条目。
    • +4312345677匹配0个条目。
    • +431234567匹配2个条目:“空:公司A”&;“890:公司A中的员工”
    • 在这两个匹配项中,“77”不匹配任何内容,因此返回空的扩展名:“company a”。

    实施说明

    如上所述,该算法确实存在一些效率问题。如果数据库查找成本很高,则它具有与电话号码长度相关的线性成本,特别是在数据库中不存在类似号码的情况下(例如,如果传入号码来自哈萨克斯坦,但数据库*8中没有哈萨克斯坦号码)。

    不过,您可以相对容易地添加一些优化。如果与你打交道的大多数公司都使用3或4位扩展名,你可以先从末尾去掉4位数字,然后进行二进制切分,直到你找到答案。在许多情况下,这会将15位数减少到4或5,最多可以查找6次。

    此外,每次缩小选择范围时,都只能在上一个选择范围内进行选择,而不必在整个数据库中进行选择。

    附加实施说明

    终于弄明白了 Unreason's answer 好的,我可以看到这是一个更简单,更优雅的解决方案。我希望我能简单地在输入的号码中查找数据库号码,而不是相反。

    我唯一关心的是 telephonenumber 在数据库中可能会对服务器施加过多的要求。我建议在最大压力下对该解决方案进行基准测试,看看它是否会导致问题。如果不是,那就用这个。如果是的话,考虑实现我算法的简单形式并再次进行压力测试。如果性能仍然太低,请尝试我的二进制搜索建议。

        2
  •  4
  •   HansDampf    14 年前

    有没有办法确定存储号码的哪一部分是分机? 或者是没有扩展的“基数”被存储。 如果是,您可以检查数据库中的数字(不带扩展名)是否是要检查的当前数字的前缀。 前缀是指从开头开始的字符串的子字符串。

    但是如果你的数据库中只有带扩展名的数字,而且没有办法找出有多少个数字属于它,我相信你找不到确切的答案。

        3
  •  2
  •   Mark Booth    12 年前

    不必在数据库中查找电话号码,您可以反转问题并检查数据库中的每个号码,看是否匹配 或前缀 输入的号码。

    假设你从来电显示中得到一个电话号码,比如+431234567891,那么

    SELECT name, id
    FROM Table
    WHERE CHARINDEX(telephonenumber, "+431234567891") > 0;
    

    将返回公司,在+431234567890的情况下将返回2个记录

    • 公司
    • 实际扩展

    如果您可以处理从客户端返回的两行,那么您应该可以处理上面的问题。

    预处理数据更好(性能方面),但为此您需要更详细地描述数据,例如:

    • 分机只有3和4位吗?
    • 基数总是9或10位数,
    • 对于有分机的公司,你总是至少有一个分机号码吗?
        4
  •  1
  •   ChrisW    14 年前

    分机中的位数是特定于PBX的。 区号+电话号码中的数字位数取决于国家/运营商。

    一种方法是定义额外的规则,例如…

    +43123 12

    …要说以+43123开头的任何内容都是一个12位数的数字,超出这个数字的任何内容都是一个扩展:这允许您使用(可配置的而不是硬编码的)数据来指定扩展的开始位置。

    另一种方法可能是坚持对于任何带有扩展项的数字,也应该有一个没有扩展项的对应数字,如您的“公司A”示例所示。

        5
  •  1
  •   Benjamin Podszun    14 年前

    好吧,我对电话号码系统的理解是,如果一个号码是另一个号码的前缀,那么就不可能存在两个有效/完整的号码。这里一个常见的恶作剧是把你的电话号码打成110532或其他什么,其中110是德国紧急警察的号码。

    因此-如果您可以更改数据库结构并对数据进行预处理,那么您可以查找具有相同前缀的数字(如果较长的数字以最短的为扩展名,请先排序)。每一场比赛

    • 基数(最短的)
    • 直拨号码加分机号码(都是长的)

    如果可能的话,我会在数据库中标记这些以便更快地查找。

    这种方法不适用于具有通用默认扩展名的情况。在这里,很多公司都会将1234567-0作为外部号码,其中0可以替换为2-4位的扩展名。在这些情况下,我的方法可能会有缺陷——但对于你的示例数据,它会起作用吗?

        6
  •  1
  •   Nelson Rothermel    14 年前

    如果你要处理来自不同国家的电话号码,那几乎是不可能的。即使在同一个国家,长度也经常变化。如果你知道长度是多少(或者你想维护chrisw这样的列表),你可以在搜索公司的电话号码之前使用left(field,x)函数截断电话号码。注意,如果您正在执行联接,它可能会运行得慢得多,因为它必须在每一行上运行函数。

        7
  •  -1
  •   MartinStettner    14 年前

    如果没有进一步的信息,这将是不可能的:如果您的表是如上所述的结构,那么系统将无法知道哪个部分是基数,哪个部分是扩展名。因此它将返回“公司B”,以“+439”开头的任何(未知)号码。

    编辑 (@markbooth)

    我坚持我的主张,没有额外的信息是不可能的。只是为了更清楚:假设我们的数据库中有以下信息

    ...
    +43316852132 - ....
    +433168731 - Company A (reception)
    +433168739999 - Company A, Mr. X
    +433168911321 - ....
    ...
    

    这些数字的结构是+43(316)873-1,程序不知道。因此,如果一个号码+43316872133(+43(316)872133(带结构)正在呼叫(不在数据库中),则在没有进一步信息的情况下,您(因此您的软件:)无法判断它是否属于A公司。

    唯一的解决方案是为公司维护“基数”,您可以对其进行简单的前缀搜索。