使用Java将电话号码转换为国际格式(E.164)的最佳方法是什么?

使用Java将电话号码转换为国际格式(E.164)的最佳方法是什么?

鉴于“电话号码”和国家/地区ID(假设是ISO国家/地区代码),我想将其转换为标准的E.164国际格式电话号码。

我相信我可以很容易地手工完成 – 但我不确定它在所有情况下都能正常工作。

您建议使用哪个Java框架/库/实用程序来完成此任务?

PS“电话号码”可以是公众可识别的任何内容 – 例如

* (510) 786-0404 * 1-800-GOT-MILK * +44-(0)800-7310658 

最后一个是我最喜欢的 – 这是有些人在英国写他们的号码并且意味着你应该使用+44,或者你应该使用0。

E.164格式编号应全部为数字,并使用完整的国际国家代码(例如+ 44)

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)); 

从写这种东西的经验来看,100%可靠性真的很难做到。 我已经编写了一些Java代码,这些代码在处理我们拥有的数据方面相当不错,但并不适用于每个国家/地区。 您需要问的问题是:

数字映射的字符在各国之间是否一致? 美国使用了很多(例如1800-GOT-MILK),但在澳大利亚,作为一个例子,它非常罕见。 您需要做的是确保您正在为相关国家/地区做正确的映射(如果它有所不同)(可能没有)。 我不知道哪些国家使用不同的字母表(例如俄罗斯的Cyrilic和前东方国家);

你必须接受你的解决方案不是100%,你不应该期望它。 你需要采取“最好的猜测”方法。 例如,没有真正的方式知道132345是澳大利亚的有效电话号码,1300 123 456也是如此,但这些只是13xx号码的两种模式,而且它们不能从海外打电话;

您还必须询问是否要validation区域(区域代码)。 我相信美国使用的区域代码的第二个数字是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(one),deux(two),trois(three),…

它的

douze(十二),trente-quatre(三十四),…

您想要迎合这种文化差异吗? 我会假设没有,但这个问题值得考虑,以防万一你的规则过于严格。

也有些人可能会在电话号码上附加分机号码,可能带有“分机”或类似的缩写。 你想要迎合这个吗?

对不起,这里没有代码。 只是一系列问题要问自己和需要考虑的问题。 正如其他人所说的那样,一系列正则表达式可以完成上述的大部分工作,但最终电话号码字段(大部分)是在一天结束时(通常)自由格式的文本。

这是我的解决方案:

 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(" ", ""); } 

我希望这可以帮助有同样问题的人。

享受和自由使用。

谢谢你的回答。 正如原始问题中所述,我更感兴趣的是将数字格式化为标准格式,而不是确定它是否是有效(如真实的)电话号码。

我目前有一些手工编写的代码,它带有一个电话号码字符串(由用户输入)和一个源国家/地区背景和目标国家/地区背景(拨打该号码的国家/地区以及拨打该号码的国家/地区) – 这是系统已知的)然后按步骤进行以下转换

  1. 从数字中删除所有空格

  2. 将所有阿尔法翻译成数字 – 使用字母到数字的查找表(例如A – > 2,B – > 2,C – > 2,D – > 3)等键盘(我不知道)一些键盘以不同方式分发这些键盘)

  3. 删除所有标点符号 – 如果存在,则保持前面的“+”完整(如果该数字已经是某种国际格式)。

  4. 确定该号码是否具有国家/地区背景的国际拨号前缀 – 例如,如果源上下文是英国,我会看到它是否以’00’开头 – 并将其替换为’+’。 我目前不检查’00’后面的数字是否跟随目标国家/地区的国际拨号代码。 我在查找表中查找源国家的国际拨号前缀(例如GB – > ’00’,US – >’011’等)

  5. 确定该号码是否具有国家/地区上下文的本地拨号前缀 – 例如,如果源上下文是英国,我会查看它是否以“0”开头 – 并将其替换为“+”后跟国际拨号目标国家/地区的代码。 我在查找表中查找源国家/地区的本地拨号前缀(例如GB – >’0’,US – >’1’等),以及另一个查找表中目标国家/地区的国际拨号代码( eg’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标准格式,并且转换全部在软件中完成。

说实话,听起来你已经掌握了大部分基础。

英国有时(错误地)使用的+44(0)800格式令人讨厌,并且根据E.123不是严格有效的,这是ITU-T关于如何显示数字的建议。 如果您还没有E.123的副本,那值得一看。

对于它的价值,电话网络本身并不总是使用E.164。 通常在PBX(或者如果你在蒸汽电话上的网络中)生成的ISDN信令中会有一个标志,它告诉网络拨打的号码是本地的,国内的还是国际的。

这是一项非常困难的任务,因为每个国家的电话号码写得差别很大。

我们曾经保留一份REGEXP列表(我们支持19种格式)来解析数字的3个部分,然后将这3部分转换为“+ {1} {2} {3}”。

首先按照更具体的方式对regexp进行排序,然后选择成功解析的第一个regexp。

在某些国家/地区,您可以将112validation为有效的电话号码,但如果您在其前面粘贴国家/地区代码,则它将不再有效。 在其他国家/地区,您无法validation112,但您可以将911validation为有效的电话号码。

我见过一些手机将Q放在7键上,Z放在9键上。 我见过一些把Q和Z放在0键上的手机,还有一些把Q和Z放在1键上。

昨天存在的区号可能今天不存在,反之亦然。

在北美的一半(国家代码1),区域代码的第二个数字规则曾经是0或1,但该规则在10年前消失了。

我不知道可用于将电话号码格式化为E.164的标准库或框架。

用于我们产品的解决方案需要将调用者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 

我们执行类似于您所描述的操作,即剥离所提供的任何非数字字符的电话号码,然后根据有关总体数量计划长度,外部访问代码和长途/国际访问代码的各种规则进行格式化。