libphonenumber-js
用 javascript 重写了 Google Android 的 libphonenumber
库,更简单、更小巧。
LibPhoneNumber
libphonenumber
是 Google 发布的一个电话号码格式化和解析库,最初是为 Google 的 Android 手机操作系统开发的(目前使用的是该系统)。
libphonenumber-js 是对原来的 libphonenumber 库(用 C++ 和 Java 写的,因为这些都是 Android 操作系统使用的编程语言)的“轻量级”纯 javascript 重写。虽然 libphonenumber 有一个由 Google 维护的 官方自动生成的 javascript 移植,但它与 Google 的 closed javascript 实用框架紧密耦合。它仍然可以被编译成一个巨大的捆绑包,高达 530 千字节(330 kB 代码 + 200 kB 元数据)-- 对于一个普通网站上的一个简单的电话号码输入字段来说,这已经是相当大的了。
与谷歌 libphonenumber 的区别
占用空间更小。130千字节(55 kB 代码 + 75 kB 足够的元数据),而原来 Google 的 530 千字节(330 kB 代码 + 200 kB 完整元数据)。
可以在文本中搜索电话号码(Google的自动生成的javascript端口不能)。
不解析字母电话号码,如 1-800-GOT-MILK。
不解析或格式化特殊的 "本地 "专用电话号码:"本地 "区域(例如,一个城市)特有的号码,但省略了 "区域代码"(如456-789,省略了 "区域代码"(123),而不是完整的(123)456-789号码),紧急电话号码,如911,"短码"(仅限短信的短号码),以*开头的号码(如*555)等。
在格式化国际电话号码时,不使用连字符和括号(看起来更干净)。
对 "非地理 "电话号码不使用 "001 "国家代码。取而代之的是,PhoneNumber 类有一个 .isNonGeographic() 方法。
GitHub Ban
2020年3月9日,GitHub 公司在没有任何通知的情况下,默默地 banned 了我的账户(以及我所有的库),原因不明。我开了一个支持工单,但他们没有回复。因为这个原因,我不得不把我所有的库都转移到 GitLab 上。
安装
通过 npm
$ npm install libphonenumber-js --save
通过 yarn
$ yarn add libphonenumber-js
如果你没有使用绑定包,那么就使用 CDN 的独立版本。
"min" vs "max" vs "mobile" vs "core"
这个库需要选择一个"元数据"集来使用,"元数据"是所有国家的电话号码解析和格式化规则列表。完整的规则列表非常庞大,所以这个库提供了一个优化捆绑大小的方法,可以在 max、min、mobile 和自定义元数据之间进行选择。
- max -- 完整的元数据集,大小约为 140 千字节(libphonenumber-js/metadata.full.json)。当你需要一个严格版本的 isValidPhoneNumber(value) 函数时,或者当你需要获取电话号码类型(固定电话、移动电话等)时,请选择这个。
- min -- (默认)最小的元数据集,大小约为 75 千字节(libphonenumber-js/metadata.min.json)。不包含用于大多数国家的高级电话号码验证(.isValid())和确定电话号码类型(.getType())的正则表达式。通过 .isValid() 进行的一些简单的电话号码验证仍然有效(基本的长度检查等),只是与"高级"验证(没有那么严格)相比,它是松散的。默认选择:当你不需要获取电话号码类型时(固话、移动等),或者当非严格版本的 isValidPhoneNumber(value) 函数就足够了。
- mobile -- 仅用于处理手机号码的完整元数据集,大小约为 105 kb(libphonenumber-js/metadata.mobile.json)。当你只处理移动号码,并且需要一个严格版本的 isValidPhoneNumber(value) 函数来验证移动号码时,请选择这个。
要使用特定的元数据集,请从相关的子包中导入函数:libphonenumber-js/max、libphonenumber-js/min 或 libphonenumber-js/mobile。
直接从 libphonenumber-js 导入函数的结果是使用 min 元数据,这意味着对于大多数国家来说,通过 .isValid() 进行松散(非严格)的电话号码验证,并且不能通过 .getType() 获取电话号码类型。
有时(很少)并不是所有的国家都需要,在这种情况下,开发者可能想生成自己的"自定义"元数据集。对于这些情况,libphonenumber-js/core 子包没有预装任何默认的元数据,而是接受元数据作为每个导出函数的最后一个参数。
使用
解析电话号码
import { parsePhoneNumberFromString } from 'libphonenumber-js' const phoneNumber = parsePhoneNumberFromString('Phone: 8 (800) 555 35 35.', 'RU') if (phoneNumber) { phoneNumber.country === 'RU' phoneNumber.number === '+78005553535' phoneNumber.isValid() === true phoneNumber.getType() === 'TOLL_FREE' }
格式化电话号码
import { parsePhoneNumberFromString } from 'libphonenumber-js' const phoneNumber = parsePhoneNumberFromString('+12133734253') phoneNumber.formatInternational() === '+1 213 373 4253' phoneNumber.formatNational() === '(213) 373-4253' phoneNumber.getURI() === 'tel:+12133734253'
键入时格式化
import { AsYouType } from 'libphonenumber-js' new AsYouType().input('+12133734') // Outputs: '+1 213 373 4' new AsYouType('US').input('2133734') // Outputs: '(213) 373-4'
全文搜索
import { findPhoneNumbersInText } from 'libphonenumber-js' findPhoneNumbersInText(` For tech support call +7 (800) 555-35-35 internationally or reach a local US branch at (213) 373-4253 ext. 1234. `, 'US') // Outputs: // // [{ // number: PhoneNumber { // country: 'RU', // countryCallingCode: '7', // number: '+78005553535', // nationalNumber: '8005553535' // }, // startsAt : 22, // endsAt : 40 // }, { // number: PhoneNumber { // country: 'US', // countryCallingCode: '1', // number: '+12133734253', // nationalNumber: '2133734253', // ext: '1234' // }, // startsAt : 86, // endsAt : 110 // }]
定义
国家代码
"国家代码 "指的是 两个字母的 ISO 国家代码(如 US)。
非地理代码
有好几个电话号码是不属于任何国家的。
+800
-- 国际免费电话+808
-- 通用国际分摊费用号码+870
-- Inmarsat Global Limited+878
-- 通用个人电信+881
-- 全球移动卫星系统+882
和+883
-- 国际网络+888
-- 联合国人道主义事务协调厅+979
-- 国际高级费率服
这样的电话号码计划被称为"非地域性",其电话号码的 country 设置为 undefined。
国家(重要)号码
"全国(重要)号码"是指全国电话号码位数(不含"全国前缀")。例如,+1 213 373 4253(或(213)373-4253的国家格式)是一个美国电话号码,其国家(重要)号码是 213 373 4253。另一个例子是 +33 1 45 45 32 45(或 01 45 45 32 45 的国家格式),这是一个法国电话号码,当他们写国家格式的电话号码时,他们添加 0 "国家前缀";在这种情况下,国家(重要)号码是 1 45 45 32 45。
国家电话代码
"国家呼叫代码"是指当号码以国际格式书写时,+ 和国家(重要)号码之间的数字。如:美国的国家呼叫代码是 1,法国的国家呼叫代码是 33。几个国家可以共用同一个 "国家呼叫代码",如美国和加拿大等 NANPA 国家共用同一个 1 国家呼叫代码。
API
(恕删略。请参见自述文件)
使用电话号码验证功能
我个人在项目中不使用严格的电话号码验证,因为电话号码计划有时会发生变化,所以验证规则也会发生变化,这意味着如果一个网站不定期重新部署,PhoneNumber.isValid() 函数可能会变得过时。比如说:
- 新的电话号码规则可能会被添加到 Google 的 libphonenumber 库中,而这些规则已经在现实生活中实现了(这可能会带来延迟)。
- 之后那些来自 Google 的 libphonenumber 的新规则会被合并到这个库中(又是一个延迟)。
- 还有就是 web 应用本身也在使用这个库,在开发者手动安装 libphonenumber-js@latest 并重新构建和部署 web 应用之前,它将使用旧的(可能是过时的)电话号码验证规则,如果网站表单对用户输入的验证过于严格,可能会导致失去新的有效(但以前不是有效)电话号码的稀有客户。
电话号验证规则在 Google 的 repo 中定期更新。想象一下,一个网站应用(例如 "促销网站"或 "个人网站")的 "联系我们"表单部署一次,然后运行多年,没有任何维护。
如果需要验证用户输入的电话号码,那么我个人会使用类似 PhoneNumber.isPossible() 这样只验证电话号码长度的东西。
React
还有一个利用这个库的 React 组件 -- react-phone-number-input
(或不含国家选择)。
错误报告
当报告一个问题时,还必须提供 Google 的 libphonenumber 演示页面的链接,说明预期的行为。这包括验证、解析、格式化和键入时的格式化。例如,对于一个澳大利亚数字 438 331 999,Google 的演示会输出四个部分 -- "解析结果"、"验证结果"、"格式化结果"和 "AsYouTypeFormatter 结果"。在 bug 报告中,首先描述观察到的 libphonenumber-js 演示结果,然后描述 Google 的演示结果(并附上链接),该结果必须与观察到的 libphonenumber-js 演示结果不同。如果观察到的 libphonenumber-js 演示结果与 Google 的演示结果相同,而你不同意 Google 的演示结果,那么就在 Google 的 Google's repo 中创建一个问题。
当报告 findPhoneNumbersInText() bug 时,应该知道 findPhoneNumbersInText() 代码是从 Google 的 Java 代码移植过来的。我不是自己写的,只是移植过来的。因此,除了 Google 之外,其他任何人都不可能修复这样的 bug。
TypeScript
这个库的 TypeScript 支持 完全是由社区驱动的。我自己不使用 TypeScript。发送你的拉取请求。
CDN
可以使用任何 npm CDN 服务,例如 unpkg.com 或 jsdelivr.com。
<script src="https://unpkg.com/libphonenumber-js@[version]/bundle/libphonenumber-[type].js"></script> <script> alert(new libphonenumber.AsYouType('US').input('213-373-4253')) </script>
其中 [version] 是 npm 软件包的版本范围 (例如,1.x 或 ^1.7.6),[type] 是 bundle 类型:min、max 或 mobile。
元数据
元数据是通过将 XML 转化为 JSON 并删除不必要的字段,从 Google 的原始 PhoneNumberMetadata.xml
生成的。参见元数据字段描述。
元数据更新过程是通过 "autoupdate" 脚本自动完成的(参见 ./autoupdate.sh或 ./autoupdate.cmd)。该脚本检测 Google libphonenumber 的 repo 中 PhoneNumberMetadata.xml 的变化,如果有变化,那么它就会拉出最新的元数据,进行处理,将变化提交到 GitHub,构建新版本的库,并发布到 NPM。所以这个库的元数据应该是最新的。我可以设置这个脚本自动运行,但在我的 Windows 机器上,ssh-agent 不能正常工作,所以我时常手动运行 "autoupdate" 脚本。
自定义元数据
这个库预装了三种类型的元数据。
- metadata.full.json -- 包含所有内容,包括所有用于精确电话号码验证和获取电话号码类型的正则表达式,但大小约为140kb。
- metadata.min.json -- (默认)最小的一个,不包含用于精确电话号码验证和获取大多数国家电话号码类型的正则表达式,大小约为75千字节。
- metadata.mobile.json -- 是 "完整" 的元数据,只支持手机号码,大小约为105kb。
有时,如果在一个项目中只需要一组特定的国家,而开发者真的想减少由此产生的捆绑包大小,比如说,减少 50 千字节(即使包括所有用于精确验证电话号码和获取电话号码类型的正则表达式),那么他们可以生成这样的自定义元数据,并将其作为最后一个参数传递给这个库的 "核心"(过去称为 "自定义")函数。
参见生成自定义元数据说明。
>然后将生成的 metadata.custom.json 文件与 "核心"函数一起使用。
传统:如何使用生成的 metadata.custom.json 文件与传统的 "自定义" 函数。
每次部署项目时都应该重新生成元数据,因为 Google 会不断更新他们的元数据。
维护
谷歌会定期发布新的元数据,其变化在发布说明中有所描述。有时这些是小的非破坏性更新,有时是主要版本的破坏性更新。元数据应该通过 autoupdate.cmd (Windows) 和 autoupdate.sh (Linux/macOS) 脚本定期更新。另外 Google 有时(很少)会更新他们的代码:phonenumberutil.js
(parseNumber(),formatNumber(),isValidNumber(),getNumberType()),asyoutypeformatter.js
(AsYouType),PhoneNumberMatcher
(findPhoneNumbersInText())。最近一次同步是在2020年1月19日。
贡献
克隆这个 Repo 后,通过运行确保依赖关系被安装。
npm install
该模块是用 ES6 编写的,并使用 Babel 进行 ES5 的移植。通过运行本模块,可以生产出广泛消耗的 JavaScript。
npm run build
一旦 npm 运行构建,你可以直接从 node 导入或 require()。
开发完成后,可以通过运行完整的测试套件进行评估。
npm test
测试覆盖率必须保持在 100%。
npm run test-coverage
当你准备好在一个真实的项目上测试你的新功能时,你可以运行
npm pack
它将构建、测试并创建一个 .tgz 存档,然后你可以将其安装到你的项目文件夹中。
npm install [module name with version].tar.gz
广告
如果您正在寻找一个国际性的 "2天前" javascript 解决方案,那么请查看 javascript-time-ago
。
许可证
(The first version translated by vz on 2020.08.30)