国际手机号码的有效性校验

手机号码,越来越多的用于网站注册/绑定联系方式。

存储/验证手机号码的格式, 本应该是一个很简单的事情。

根据 ITU-T(国际电联电信标准化部门) 的 E.164 标准做就好了。

然而,恰如浏览器之于 web 前端标准。 总会有万万想不到。

手机号码的 "万万想不到" 们

手机号码的有效性验证之复杂, Google 开源了一个 library。

其中,列举了 25万万想不到

比如:

手机号码,不一定都是 ASCII 字符。 埃及的手机号码,经常写成象形文字 (native digits)。

In Egypt, it is common for phone numbers to be written in native digits.

你好,我的电话号码是:

Egypt-1000000 Egypt-1000000 Egypt-1000000 Egypt-1000000 Egypt-1000000 Egypt-1000000

深入研究埃及象形文字,点 Egyptian numeralsEgypt-1000000 是 1000000。

看似简单的几个问题,似乎并不容易

  • 数据库设计时,应该考虑的最长手机号码是多少位
  • 最短的手机号码,多少位
  • 如何设计用户体验友好的手机号码输入界面
  • 如何验证手机号码的有效性

最长手机号码是多少位

根据 ITU-T 制定的 E.164 标准,最长 15 位。 其中 1-3 位是国家码。

根据 Google i18n,德国已经分配了超过这个长度的手机号码。

stackoverflow 上的讨论

What's the longest possible worldwide phone number I should consider in SQL varchar(length) for phone

一般推荐的安全长度是 20。

数据库设计时,推荐 varchar 的长度为 50。

稍微冗余一点,以防万一。过度优化是万恶之源。

最短的手机号码多少位

stackoverflow 上的讨论

What is the minimum length of a valid international phone number?

不同的国家,不一样。

瑞士的,似乎最短,有 8 位的。

如何验证手机号码的有效性

连国家码一起,用一个正则?

如果包括国家码, 同一个手机号码,可能有以下几种写法:

  • 008610-85912411
  • (008610)85912411
  • (0086) 10-85912411
  • +8610-85912411
  • +86-10-85912411

试图用一个正则来校验,是不可能做到的。

不同的国家,规则相同?

用户输入一个 10 位的手机号码, 这个号码,是否合法?

有一些国家,手机号码是 10 位的。 如果用户来自中国, 90% 的可能,是用户少输入了 1 位数字。

如果我们没有第一时间发现,而是用户填了很多信息,甚至账号注册几个月之后才发现, UX 是很差的。 这也给后台用户系统的设计带来了非常大的挑战。

我的建议是:要么不校验,要么针对国家定制匹配规则。

如何设计用户体验友好的手机号码输入界面

分析校验规则的时候, 已经讨论的很清楚了。

一定是 2 个输入框。

  • 国家码。推荐使用下拉框
  • 手机号码。根据选中的国家码,做有效性校验。

如果技术上有条件,加发送短信验证码的按钮。

github 的例子如下:

github-phone-input

校验规则

可参考 Google 开源的 libphonenumber

Quick Examples

boolean isValid = phoneUtil.isValidNumber(swissNumberProto); // returns true

There are a few formats supported by the formatting method, as illustrated below:

// Produces "+41 44 668 18 00"
System.out.println(phoneUtil.format(swissNumberProto, PhoneNumberFormat.INTERNATIONAL));
// Produces "044 668 18 00"
System.out.println(phoneUtil.format(swissNumberProto, PhoneNumberFormat.NATIONAL));
// Produces "+41446681800"
System.out.println(phoneUtil.format(swissNumberProto, PhoneNumberFormat.E164));

You could also choose to format the number in the way it is dialed from another country:

// Produces "011 41 44 668 1800", the number when it is dialed in the United States.
System.out.println(phoneUtil.formatOutOfCountryCallingNumber(swissNumberProto, "US"));

总结

  • 数据库设计时,推荐 varchar 的长度为 50。
  • 用户输入界面,国家码和手机号码分开。
  • 国家码的输入界面,推荐下拉框。
  • 编写手机号码的有效性验证规则时,按国家写。可参考 Google 开源的 libphonenumber

Comments