是否有用于在数据库中存储规范化电话号码的标准?


95

在数据库字段中存储电话号码的良好数据结构是什么?我正在寻找一种足够灵活的方式来处理国际号码,同时也希望能够有效查询号码的各个部分。

编辑:这里只是为了阐明用例:我目前将数字存储在单个varchar字段中,并且在客户输入时将其保留。然后,当代码需要数字时,我将其标准化。问题是,如果我想查询几百万行以查找匹配的电话号码,它涉及到一个功能,例如

where dbo.f_normalizenum(num1) = dbo.f_normalizenum(num2)

这是非常低效的。当查询只是区号时,寻找区号之类的查询也会变得非常棘手。

[编辑]

人们在这里提出了很多好的建议,谢谢!作为更新,这是我现在正在做的事情:我仍然将输入的数字完全存储在varchar字段中,但是我没有在查询时对数据进行规范化,而是有一个触发器,可以在插入记录时完成所有工作或更新。因此,对于需要查询的任何部分,我都有ints或bigints,并且对这些字段进行了索引以使查询运行更快。


这个问题的当代答案是在这里-stackoverflow.com/a/51761170/968003。要点-使用RFC 3966进行存储,使用libphonenumber进行解析/验证。
亚历克斯·克劳斯

Answers:


80

首先,除了国家/地区代码之外,没有真正的标准。最好的办法就是通过国家/地区代码识别特定电话号码属于哪个国家/地区,然后根据该国家/地区的格式处理其余的号码。

但是,通常电话设备等是标准化的,因此您几乎总是可以将给定的电话号码分解为以下部分

  • C国家/地区代码1到10位数字(目前为4或更少,但可能会更改)
  • 区域代码(省/州/地区)代码0到10位数字(实际上可能需要一个区域字段和一个区域字段,而不是一个区域代码)
  • E交换(前缀或交换机)代码0-10位
  • L行号1-10位

使用此方法,您可以潜在地分隔数字,例如,您可以找到由于彼此具有相同的国家,地区和交换代码而可能彼此接近的人。使用手机已不再是您可以指望的东西。

此外,每个国家内部都有不同的标准。在美国,您始终可以依赖(AAA)EEE-LLLL,但是在另一个国家,您可能在城市(AAA)EE-LLL中有交换所,而在农村地区(AAA)LLLL中则只有行号。您将必须从某种形式的树的顶部开始,并在掌握信息时对其进行格式化。例如,国家/地区代码0具有其余号码的已知格式,但是对于国家/地区代码5432,您可能需要先检查区号,然后才能了解其余的号码。

您可能还需要处理vanity数字,例如(800) Lucky-Guy,这需要确认,如果是美国数字,则数字太多(您可能需要完整地代表广告或其他目的),而在美国,字母映射到数字与德国不同。

您可能还希望将整个数字分别存储为文本字段(国际化),以便稍后再返回并根据情况变化重新解析数字,或者作为备份,以防有人提交了错误的方法来解析特定国家/地区的格式并丢失信息。


1
知道有没有很好的JavaScript验证来尝试对此进行验证?
cmcculloh

6
E164对号码的长度设置了更严格的限制:国家/地区为1-3,最大长度为15。知道全球电话系统后,这不会很快改变。
丰富

根据ITU-T E.164,您指定的长度似乎完全错误。如果您可以发布指向标准文档的链接(从中获取您的信息)或解释为什么E.164不适用,这将很有帮助。
Abtin Forouzandeh,2009年

5
@Abtin-并非每个电话系统都符合ITU-T E.164。但是,其中绝大多数人都这样做,值得权衡选择符合标准,将某些人拒之门外或超出标准所规定的范围并接受所有人之间的选择。注意,E.164可以看作是上述方案的子集。不过,我认为最好的格式是用户准确输入的格式,然后有一种解析算法在需要时将其标记化,而不是将标记化的形式存储在数据库中。
亚当·戴维斯

1)可以假设所有国际号码都符合具有CAE组件的规定吗?2)您能否假设C组件是唯一不同的对象,具体取决于您从哪里拨号。例如,美国号码850-555-1234具有A = 850和E = 555-1234,如果从美国拨打,则C = 1,如果从英国拨打,则C = 001。要点是无论您从哪里拨号,A和E都不会动态变化,对吗?
AaronLS '16

55

吻-我已经厌倦了许多美国网站。他们编写了一些巧妙的代码来验证邮政编码和电话号码。当我输入完全有效的挪威联系信息时,我发现它经常被拒绝。

保留字符串,除非您对某些更高级的内容有特定的需求。


一个不错的老将,nvarchar(42)并且经过一点验证,/^+?[0-9 -\.\(\)#*]{4,41}$/效果很好!
SandRock 2012年

我同意,但同时不同意。通常,您想对存储的电话号码进行处理,例如显示它。与其走这条试图解析足够多的路来显示它的方式,还不如以一种标准化的方式存储它。现在,我并不是说我们应该在区域代码周围加括号。我想说的是,这一切都没有数字破折号等
松饼人

4
我相信电话号码应在存储之前进行解析,以便可以对其进行验证和以规范化的方式进行存储。googlei18n / libphonenumber完全可以对电话号码进行国际解析和格式化。
Roel

21

E.164上Wikipedia页面应告诉您所有您需要了解的内容。


3
不,该标准仅定义了电话号码的结构(它们由三个数字组成),但没有指定如何显示和/或存储电话号码。我说标准了吗?我的意思是推荐
BlueWizard

8

这是我建议的结构,感谢您的反馈:

电话数据库字段应为具有以下格式的varchar(42):

国家/地区代码-数字x扩展名

因此,例如,在美国,我们可以:

1-2125551234x1234

这将代表具有区号/号码(212)555 1234和扩展名1234的美国号码(国家代码1)。

用破折号分隔国家/地区代码可以使正在阅读数据的人可以清楚地看到国家/地区代码。这不是严格必需的,因为国家/地区代码是“ 前缀代码 ”(您可以从左到右阅读它们,并且始终可以明确确定国家/地区)。但是,由于国家/地区代码的长度是不同的(目前在1到4个字符之间),除非您使用某种分隔符,否则您一眼就能知道国家/地区代码。

我使用“ x”分隔扩展名,因为否则(在许多情况下)实际上不可能确定哪个是数字,哪个是扩展名。

这样,您可以将完整的数字(包括国家代码和分机号)存储在一个数据库字段中,然后用于加快查询速度,而不必像到目前为止那样费心地加入用户定义的函数。

为什么选择varchar(42)?好吧,首先,国际电话号码的长度将有所不同,因此为“ var”。我要存储一个破折号和一个“ x”,以便解释“ char”,无论如何,您不会对电话号码进行整数运算(我想),因此尝试使用数字类型几乎没有任何意义。至于42的长度,我根据亚当·戴维斯(Adam Davis)的答案使用了所有字段的最大可能长度,并在破折号和'x'处加了2。


7

查找E.164。基本上,您将电话号码存储为以国家/地区前缀和可选的pbx后缀开头的代码。那么显示就是本地化问题。验证也可以完成,但这也是一个本地化问题(基于国家/地区前缀)。

例如,+ 12125551212 + 202将在en_US语言环境中格式化为(212)555-1212 x202。en_GB或中的格式将不同de_DE

关于ITU-T E.164的信息很多,但它很神秘。


6

我个人喜欢存储标准的varchar电话号码(例如9991234567),然后在显示时内联格式化该电话号码的想法。

这样,数据库中的所有数据都是“干净的”且无格式


4

存储

商店电话在RFC 3966(如+1-202-555-0252+1-202-555-7166;ext=22)。与E.164的主要区别是

  • 长度无限制
  • 支持扩展

为了优化视图操作的性能,请以RFC 3966字段旁边的“国家/国际”格式存储电话。

除非您有充分的理由,否则请勿将国家/地区代码存储在单独的字段中。为什么?因为您不应该在用户界面上要求输入国家或地区代码。

通常,人们在听到电话时会进入电话。例如,如果本地格式将以0或开头8,那么用户在头部进行数字转换就很烦人(例如“ 确定,请不要输入'0',选择国家/地区,然后输入有人在此字段中说 “)。

解析中

Google支持您,您可以使用其libphonenumber库来验证和解析任何电话号码。几乎所有语言都有端口。

因此,让用户只需输入“ 0449053501”或“ 04 4905 3501”或“ (04) 4905 3501”即可。该工具将为您找出其余部分。

观看官方演示,以了解它有多少帮助。



3

好的,因此,根据此页面上的信息,以下是国际电话号码验证器的开始:

function validatePhone(phoneNumber) {
    var valid = true;
    var stripped = phoneNumber.replace(/[\(\)\.\-\ \+\x]/g, '');    

    if(phoneNumber == ""){
        valid = false;
    }else if (isNaN(parseInt(stripped))) {
        valid = false;
    }else if (stripped.length > 40) {
        valid = false;
    }
    return valid;
}

宽松地基于此页面上的脚本:http : //www.webcheatsheet.com/javascript/form_validation.php


2

数字格式化的标准是e.164,您应该始终以这种格式存储数字。您绝对不应将分机号与电话号码放在同一字段中,而应将其分开存储。至于数字还是字母数字,这取决于您将要处理的数据。


1

我认为自由文本(也许是varchar(25))是使用最广泛的标准。这将允许使用任何格式,无论是国内格式还是国际格式。

我想主要的驱动因素可能是您查询这些数字的准确程度以及您对它们的处理方式。


这遗漏了问题的重点,那就是标准化DB字段的内容以确保唯一匹配。如何查询用户可以输入“(800)555-1212”,“ + 1.800.555.1212”或其他等效值的电话号码800-555-1212是否匹配?这就是要解决的挑战。
Irongaze.com,2016年

1

我发现大多数Web表单正确地允许输入国家代码,区号,然后是其余的7位数字,但几乎总是忘记允许输入扩展名。这几乎总是使我发脾气,因为在工作中我们没有接待员,需要我的分机号联系我。


1

我发现大多数Web表单正确地允许输入国家代码,区号,然后是其余的7位数字,但几乎总是忘记允许输入扩展名。这几乎总是使我发脾气,因为在工作中我们没有接待员,需要我的分机号联系我。

我必须检查一下,但我认为我们的数据库架构是相似的。我们保存有国家代码(不确定,可能默认为美国),区号,7位数字和扩展名。


1

如何存储一个自由文本列,该列显示电话号码的用户友好版本,然后存储一个标准化版本,该版本删除空格,方括号并扩展“ +”。例如:

使用者友善: +44(0)181 4642542

标准化的: 00441814642542


10
+44(0)181 4642542对谁友好?如果英国用户不习惯于拨打国际电话,他们可能不知道如何使用+44,或者不知道应该丢弃(0)的国际用户?
Mark Ba​​ker

0

我将使用自由文本字段和包含电话号码的纯数字版本的字段。我会将电话号码的表示形式留给用户,并使用标准化字段专门用于基于TAPI的应用程序中的电话号码比较,或者在尝试在电话目录中查找重复条目时使用。当然,为用户提供一种可以增加智能的输入方案(如国家代码(如有必要),区号,基本号码和分机号的单独字段)不会带来任何伤害。


0

您从哪里获得电话号码?如果要从电话网络中获取它们,则将获得一串数字以及一个数字类型和计划,例如

441234567890类型/计划0x11(表示国际E.164)

在大多数情况下,最好的办法是按原样存储所有这些内容,并进行标准化以进行显示,尽管如果要将标准化编号用作唯一键或类似键,则存储标准化编号可能会很有用。


0

用户友好:+44(0)181 464 2542规范化:00441814642542

(0)在国际格式中无效。参见ITU-T E.123标准。

美国读者使用011进行国际访问时,“标准化”格式对他们没有用。


0

根据使用需求,我使用了3种不同的方式来存储电话号码。

  1. 如果该数字仅用于人类检索而存储,则不会完全按照用户输入的方式用于搜索存储在字符串类型字段中的数字。
  2. 如果要搜索该字段,则将删除所有多余的字符,例如+,空格和方括号等,并将剩余数字存储在字符串类型字段中。
  3. 最后,如果电话号码将由计算机/电话应用程序使用,则在这种情况下,需要输入电话号码并将其存储为系统可用的有效电话号码,该选项当然是最难编码的对于。
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.