使用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)
答案 0 :(得分:49)
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));
答案 1 :(得分:10)
根据撰写此类文章的经验,100%可靠性真的很难实现。我已经编写了一些Java代码,这些代码在处理我们拥有的数据方面相当不错,但并不适用于每个国家/地区。您需要提出的问题是:
国家/地区之间的数字映射是否一致?美国使用了很多(例如1800-GOT-MILK),但在澳大利亚,作为一个例子,它非常罕见。您需要做的是确保您正在为相关国家/地区做正确的映射,如果它有所不同(可能没有)。我不知道哪些国家使用不同的字母表(例如俄罗斯的Cyrilic和前东方国家);
你必须接受你的解决方案不是100%而你不应该期望它。你需要采取“最好的猜测”方法。例如,没有真正的方式知道132345是澳大利亚的有效电话号码,1300 123 456,但这是13xx号码中唯一的两种模式,而且它们不能从海外调用;
您还必须询问是否要验证区域(区号)。我相信美国使用的区域代码的第二个数字是1或0的系统。这可能曾经是这种情况,但我不确定它是否仍然适用。无论如何,许多其他国家都会有其他规则。在澳大利亚,固定电话和移动(手机)电话的有效区号是两位数(第一位是0)。 08,03和04都是有效的。 01不是。你怎么迎合这个?你想要吗?
无论他们写多少位数,各国都会使用不同的约定。您必须决定是否要接受“规范”以外的其他内容。这些在澳大利亚都很常见:
那就是我的头脑。对于一个国家。例如,在法国,通常用数字对写出电话号码(12 34 56 78),他们也这样说:而不是:
un(one),deux(two),trois(three),...
其
douze(十二),trente-quatre(三十四),......您想要迎合这种程度的文化差异吗?我会假设没有,但这个问题值得考虑,以防万一你的规则过于严格。
也有些人可能会在电话号码上附加分机号码,可能带有“分机”或类似的缩写。你想要迎合这个吗?
对不起,这里没有代码。只是一系列问题要问自己和需要考虑的问题。正如其他人所说,一系列正则表达式可以完成上述大部分工作,但最终电话号码字段(大部分)是在一天结束时自由形式的文本。
答案 2 :(得分:3)
这是我的解决方案:
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(" ", "");
}
我希望这可以帮助有同样问题的人。
享受并自由使用。
答案 3 :(得分:1)
感谢您的回答。正如原始问题中所述,我更感兴趣的是将数字格式化为标准格式,而不是确定它是否是有效(如真实的)电话号码。
我目前有一些手工编写的代码,其中包含电话号码字符串(由用户输入)和源国家/地区背景和目标国家/地区背景(拨打该号码的国家/地区以及该号码所在的国家/地区)正在拨打 - 这是系统已知的,然后按步骤进行以下转换
从数字
将所有字母转换为数字 - 使用字母到数字的查找表(例如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是国际拨号前缀) US和1是美国的国际拨号代码,1-123-456-7890(其中1是美国的本地拨号前缀),甚至是456-7890(假设我当时在123区号中)并且每次都得到相同的结果。我假设在内部这些拨打的号码被转换为相同的E.164标准格式,并且转换都是在软件中完成的。
答案 4 :(得分:1)
说实话,听起来你已经掌握了大部分基础。
英国有时(错误地)使用的+44(0)800格式令人烦恼,并且根据E.123不是严格有效的,这是ITU-T关于如何显示数字的建议。如果您还没有获得E.123的副本,那么值得一看。
对于它的价值,电话网络本身并不总是使用E.164。通常在PBX(或者如果你在蒸汽电话上的网络中)生成的ISDN信令中会有一个标志,告知网络拨打的号码是本地的,国内的还是国际的。
答案 5 :(得分:0)
这是一项非常艰巨的任务,因为每个国家/地区的电话号码编写方式都不同。
我们曾经保留一份REGEXP列表(我们支持19种格式)来解析数字的3个部分,然后将这3部分转换为“+ {1} {2} {3}”。
首先按照更具体的方式对regexp进行排序,然后选择成功解析的第一个。
答案 6 :(得分:0)
在某些国家/地区,您可以将112验证为有效的电话号码,但如果您在其前面粘贴国家/地区代码,则不再有效。在其他国家/地区,您无法验证112,但您可以将911验证为有效的电话号码。
我见过一些手机将Q放在7键上,Z放在9键上。我见过一些把Q和Z放在0键上的手机,还有一些把Q和Z放在1键上。
昨天存在的区号可能今天不存在,反之亦然。
在北美的一半(国家代码1),区域代码的第二位数规则曾经是0或1,但该规则在10年前消失了。
答案 7 :(得分:0)
我不知道可以将电话号码格式化为E.164的标准库或框架。
用于我们产品的解决方案,需要将PBX提供的调用者ID格式化为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
我们执行类似于您所描述的操作,即剥离所提供的任何非数字字符的电话号码,然后根据有关总体数量计划长度,外部访问代码和长途/国际访问代码的各种规则进行格式化。