提问人:Vihung 提问时间:10/9/2008 最后编辑:Vihung 更新时间:5/13/2015 访问量:75519
使用 Java 将电话号码转换为国际格式 (E.164) 的最佳方法是什么?
What is the best way for converting phone numbers into international format (E.164) using Java?
问:
使用 Java 将电话号码转换为国际格式 (E.164) 的最佳方法是什么?
给定一个“电话号码”和一个国家/地区 ID(假设一个 ISO 国家/地区代码),我想将其转换为标准的 E.164 国际格式电话号码。
我相信我可以很容易地手动完成它 - 但我不确定它是否在所有情况下都能正常工作。
您推荐哪种 Java 框架/库/实用程序来实现此目的?
P.S. “电话号码”可以是任何公众可以识别的东西,例如
* (510) 786-0404
* 1-800-GOT-MILK
* +44-(0)800-7310658
最后一个是我最喜欢的 - 这是英国人在英国写数字的方式,这意味着你应该使用 +44 或你应该使用 0。
E.164 格式号码应全部为数字,并使用完整的国际国家代码(例如 +44)
答:
从编写这种东西的经验来看,要做到 100% 的可靠性真的很难做到。我编写了一些 Java 代码来做到这一点,这些代码在处理我们拥有的数据方面相当出色,但并非适用于每个国家/地区。您需要问的问题是:
字符到数字的映射在国家/地区之间是否一致?美国使用了很多这种(例如 1800-GOT-MILK),但在澳大利亚,例如,它非常罕见。您需要做的是确保为相关国家/地区进行正确的映射(如果它发生变化(可能不会)。我不知道使用不同字母的国家(例如俄罗斯的西里尔语和前东部街区国家)是做什么的;
你必须接受你的解决方案不会是100%的,你不应该期望它是。您需要采取“最佳猜测”方法。例如,没有真正的方法可以知道 132345 是澳大利亚的有效电话号码,就像 1300 123 456 一样,但这是 13xx 号码仅有的两种模式,它们不能从海外拨打;
您还必须询问是否要验证区域(区号)。我相信美国使用的系统是区号的第二位数字是 1 或 0。这可能曾经是这种情况,但我不确定它是否仍然适用。无论如何,许多其他国家都会有其他规则。在澳大利亚,固定电话和移动电话的有效区号为两位数(第一位是 0)。08、03 和 04 均有效。01不是。你如何满足这一点?你想吗?
各国使用不同的惯例,无论他们写多少位数字。你必须决定是否要接受“规范”以外的东西。这些在澳大利亚都很常见:
- (02) 1234 5678
- 02 1234 5678
- 0411 123 123 (但我从未见过 04 1112 3456)
- 131 123
- 13 1123
- 131 123
- 1 300 123 123
- 1300 123 123
- 02-1234-5678
- 1300-234-234
- +44 78 1234 1234
- +44 (0)78 1234 1234
- +44-78-1234-1234
- +44-(0)78-1234-1234
- 0011 44 78 1234 1234(0011是标准国际拨号代码)
- (44) 078 1234 1234 (不常见)
这只是我的头顶。对于一个国家。例如,在法国,通常将电话号码写成数字对(12 34 56 78),他们也以这种方式发音:而不是:
un(一)、deux(二)、trois(三)、...
其
杜兹(十二),特伦特-夸特(三十四),......
你想迎合这种程度的文化差异吗?我认为不会,但这个问题值得考虑,以防万一你把你的规则定得太严格。
此外,有些人可能会在电话号码上附加分机号码,可能带有“ext”或类似的缩写。你想迎合这一点吗?
对不起,这里没有代码。只是要问自己的问题和要考虑的问题列表。正如其他人所说,一系列正则表达式可以完成上述大部分工作,但最终电话号码字段(大部分)是自由格式文本。
评论
在某些国家/地区,您可以验证 112 是否为有效的电话号码,但如果您在它前面贴上国家/地区代码,它将不再有效。在其他国家/地区,您无法验证 112,但可以验证 911 是否为有效电话号码。
我见过一些手机将 Q 放在 7 键上,将 Z 放在 9 键上。我见过一些手机将 Q 和 Z 放在 0 键上,有些手机将 Q 和 Z 放在 1 键上。
昨天存在的区号今天可能不存在,反之亦然。
在北美的一半地区(国家/地区代码 1),区号的第二位数字规则曾经是 0 或 1,但该规则在 10 年前就消失了。
谢谢你的回答。如原始问题所述,我对将号码格式化为标准格式更感兴趣,而不是确定它是否是有效的(如真实)电话号码。
我目前有一些手工制作的代码,它采用电话号码字符串(由用户输入)和源国家/地区上下文和目标国家/地区上下文(拨打号码的国家/地区,以及拨打号码的国家/地区 - 这是系统已知的),然后逐步进行以下转换
从数字中去除所有空格
将所有字母转换为数字 - 使用字母到数字的查找表(例如 A-->2、B-->2、C-->2、D-->3) 等作为键盘(我不知道某些键盘的分布方式不同)
去掉所有标点符号 - 如果前面的“+”存在,请保持完整(如果数字已经采用某种国际格式)。
确定该号码是否具有国家/地区上下文的国际拨号前缀 - 例如,如果源上下文是英国,我会查看它是否以“00”开头 - 并将其替换为“+”。我目前不检查“00”后面的数字后面是否跟着目标国家/地区的国际拨号代码。我在查找表中查找来源国家/地区的国际拨号前缀(例如 GB-->'00'、US-->'011' 等)
确定该号码是否具有国家/地区上下文的本地拨号前缀 - 例如,如果源上下文是英国,我会查看它是否以“0”开头 - 并将其替换为“+”,后跟目标国家/地区的国际拨号代码。我在查找表中查找源国家/地区的本地拨号前缀(例如 GB-->'0'、US-->'1' 等),并在另一个查找表中查找目标国家/地区的国际拨号代码(例如 'GB'='44'、US='1')
到目前为止,它似乎适用于我扔给它的所有东西 - 除了 +44(0)1234-567-890 的情况 - 我将为该情况添加一个特殊情况检查。
写它并不难 - 我可以为我遇到的每个奇怪的异常添加特殊情况。但我真的很想知道是否有标准的解决方案。
电话公司似乎每天都在处理这件事。使用 PSTN 拨打号码时,我永远不会得到不一致的结果。例如,在美国(手机与固定电话的区号相同,我可以拨打 +1-123-456-7890 或 011-1-123-456-7890(其中 011 是美国的国际拨号前缀,1 是美国的国际拨号代码)、1-123-456-7890(其中 1 是美国的本地拨号前缀)甚至 456-7890(假设我当时在 123 区号)并每次获得相同的结果。我假设在内部将这些拨打的号码转换为相同的 E.164 标准格式,并且转换都是在软件中完成的。
评论
我不知道有标准库或框架可用于将电话号码格式化为 E.164。
我们的产品需要将 PBX 提供的来电显示格式化为 E.164,其解决方案是部署一个文件(数据库表),其中包含所有适用国家/地区的 E.164 格式信息。 这样做的优点是可以更新应用程序(以处理各种 PSTN 网络中所有奇怪的极端情况),而无需更改生产代码库。
该表包含每个国家/地区代码的一行,以及有关区号长度和订户长度的信息。一个国家/地区可能有多个条目,具体取决于区号和订户号码长度可能的变化。
以新西兰 PSTN(部分)拨号计划为例。
CC AREA_CODE AREA_CODE_LENGTH SUBSCRIBER SUBSCRIBER_LENGTH
64 1 7
64 21 2 7
64 275 3 6
我们所做的与您描述的类似,即去除提供的电话号码中的任何非数字字符,然后根据有关总号码计划长度、外部访问代码和长途/国际访问代码的各种规则进行格式化。
评论
老实说,听起来你已经涵盖了大部分基础。
英国有时(错误地)使用的 +44(0)800 格式很烦人,并且根据 E.123 并不完全有效,这是 ITU-T 关于数字应如何显示的建议。如果您还没有 E.123 的副本,那么值得一看。
值得一提的是,电话网络本身并不总是使用E.164。通常,在 PBX 生成的 ISDN 信令中(如果您使用的是 Steam 手机,则在网络中)会有一个标志,告诉网络所拨打的号码是本地、国内号码还是国际号码。
Google 提供了一个用于处理电话号码的库。他们用于 Android 的同一个
http://code.google.com/p/libphonenumber/
String swissNumberStr = "044 668 18 00"
PhoneNumberUtil phoneUtil = PhoneNumberUtil.getInstance();
try {
PhoneNumber swissNumberProto = phoneUtil.parse(swissNumberStr, "CH");
} catch (NumberParseException e) {
System.err.println("NumberParseException was thrown: " + e.toString());
}
// 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));
评论
这是我的解决方案:
public static String FixPhoneNumber(Context ctx, String rawNumber)
{
String fixedNumber = "";
// get current location iso code
TelephonyManager telMgr = (TelephonyManager) ctx.getSystemService(Context.TELEPHONY_SERVICE);
String curLocale = telMgr.getNetworkCountryIso().toUpperCase();
PhoneNumberUtil phoneUtil = PhoneNumberUtil.getInstance();
Phonenumber.PhoneNumber phoneNumberProto;
// gets the international dialling code for our current location
String curDCode = String.format("%d", phoneUtil.getCountryCodeForRegion(curLocale));
String ourDCode = "";
if(rawNumber.indexOf("+") == 0)
{
int bIndex = rawNumber.indexOf("(");
int hIndex = rawNumber.indexOf("-");
int eIndex = rawNumber.indexOf(" ");
if(bIndex != -1)
{
ourDCode = rawNumber.substring(1, bIndex);
}
else if(hIndex != -1)
{
ourDCode = rawNumber.substring(1, hIndex);
}
else if(eIndex != -1)
{
ourDCode = rawNumber.substring(1, eIndex);
}
else
{
ourDCode = curDCode;
}
}
else
{
ourDCode = curDCode;
}
try
{
phoneNumberProto = phoneUtil.parse(rawNumber, curLocale);
}
catch (NumberParseException e)
{
return rawNumber;
}
if(curDCode.compareTo(ourDCode) == 0)
fixedNumber = phoneUtil.format(phoneNumberProto, PhoneNumberFormat.NATIONAL);
else
fixedNumber = phoneUtil.format(phoneNumberProto, PhoneNumberFormat.INTERNATIONAL);
return fixedNumber.replace(" ", "");
}
我希望这能帮助有同样问题的人。
自由享受和使用。
上一个:实体框架验证
评论