Java libphonenumber-在不知道国家/地区代码的情况下格式化电话号码

Java libphonenumber-在不知道国家/地区代码的情况下格式化电话号码,java,libphonenumber,Java,Libphonenumber,我从一个看起来很棒的图书馆听到了很多好消息,但我发现自己处于一个微妙的境地 这是我工作过的第一个将电话号码存储在数据库中的项目 我已经读了一些关于E.164格式的书,我确实打算用这种格式在我的数据库中存储所有电话号码 我面临的问题是数据源。我无法控制数据源。我只知道我收到了一堆电话号码,它们的格式不一致。有些有国际分机,有些没有。有些有括号、连字符、前导0等,有些没有 我如何可能从上述来源提取电话号码,将其格式化为E.164,以便安全存储 我尝试过使用PhoneNumberUtil#parse(

我从一个看起来很棒的图书馆听到了很多好消息,但我发现自己处于一个微妙的境地

这是我工作过的第一个将电话号码存储在数据库中的项目

我已经读了一些关于E.164格式的书,我确实打算用这种格式在我的数据库中存储所有电话号码

我面临的问题是数据源。我无法控制数据源。我只知道我收到了一堆电话号码,它们的格式不一致。有些有国际分机,有些没有。有些有括号、连字符、前导0等,有些没有

我如何可能从上述来源提取电话号码,将其格式化为E.164,以便安全存储

我尝试过使用
PhoneNumberUtil#parse()
方法,但没有提供国家代码,因为我无法访问该信息

请看以下示例:

System.out.printLn("Number -> " + phoneNumberUtil.parse("00336555233634", null).toString())
错误类型:无效的国家/地区代码。缺少或无效的默认区域

在我的例子中,号码是法国手机的号码。我相信,如果你从法国以外的地方拨号,这两个开始的
0
是有效的

但图书馆无法理解它,因为它违反了国家代码。 这是否意味着不存在了解特定电话号码来源的方法?

文档似乎对此很清楚:

public PhoneNumber parse(CharSequence numberToParse, String defaultRegion)
@param defaultRegion我们期望数字为的区域 从…起仅当*正在解析的数字不存在时才使用此选项 以国际格式编写。*
本例中的数字将存储为默认区域的数字 提供。如果数字*保证以“+”开头 后跟国家/地区呼叫代码,然后是RegionCode.ZZ*或 可以提供null

因此,如果添加
+33

System.out.printLn("Number -> " + phoneNumberUtil.parse("+336555233634", null).toString())
那么结果自然是:

编号->国家代码:33国家编号:336555233634

如果最终用户向我的应用程序提供的电话号码不是以
+
开头,我该怎么办?我不能相信我是唯一一个在这种情况下


谢谢你的帮助

您只需要使用E164格式。这里我以挪威为例

我有一个测试用例,它测试并以一种格式给出电话号码

public static String getE164FormattedMobileNumber(String mobile, String locale)
            throws PhoneNumberFormatException {
        try {
            PhoneNumberUtil phoneUtil = PhoneNumberUtil.getInstance();
            PhoneNumber phoneProto = phoneUtil.parse(mobile, locale);
            if (phoneUtil.isValidNumber(phoneProto)
                    && phoneUtil.isPossibleNumberForType(phoneProto, PhoneNumberType.MOBILE)) {
                return phoneUtil.format(phoneProto, PhoneNumberFormat.E164);
            }
            throw new PhoneNumberFormatException(
                    "Mobile number is invalid with the provided locale");
        } catch (NumberParseException e) {
            throw new PhoneNumberFormatException("Error in parsing mobile number", e);
        }
    }
测试用例如下所示

// this is the test mobile used
    private String expectedMobileNumber = "+4746205615";
private List<String> sucessMobileNumbers;

private List<String> failMobileNumbers;

public PhoneNumberE164FormatTest() {
    sucessMobileNumbers =
            Arrays.asList(
                    "46205615",
                    "004746205615",
                    "+4746205615",
                    "4746205615",
                    "46205615",
                    "+47 46205615",
                    "462 05 615");
    failMobileNumbers = Arrays.asList("abcdsds3434", "abcdsds343?#4", "21448410", "9946739087");
}

@Test
public void e164FormattedMobileNumbersSucessCase() throws PhoneNumberFormatException {

    for (String mobileNumber : sucessMobileNumbers) {
        Assert.assertEquals(
                expectedMobileNumber,
                (PhoneNumberUtils.getE164FormattedMobileNumber(mobileNumber, NO)));
    }
}

@Test(expected = PhoneNumberFormatException.class)
public void e164FormattedMobileNumbersFailCase() throws PhoneNumberFormatException {
    for (String mobileNumber : failMobileNumbers) {
        PhoneNumberUtils.getE164FormattedMobileNumber(mobileNumber, NO);
    }
}
//这是使用的测试手机
私有字符串expectedMobileNumber=“+4746205615”;
私有列表,如手机号码;
私人名单;
公用电话号码164FormatTest(){
苏卡莫比尔数=
Arrays.asList(
"46205615",
"004746205615",
"+4746205615",
"4746205615",
"46205615",
"+47 46205615",
"462 05 615");
failMobileNumbers=Arrays.asList(“abcdsds3434”、“abcdsds343?#4”、“21448410”、“9946739087”);
}
@试验
public void e164格式化的MobileEnumbersSuccessCase()引发PhoneNumberFormatException{
对于(字符串mobileNumber:SucesmobilEnumbers){
Assert.assertEquals(
期待手机号码,
(phonenumberrutils.gete164格式化的mobileNumber(mobileNumber,NO));
}
}
@测试(预期=PhoneNumberFormatException.class)
public void e164格式化的MobileEnumbersFailCase()引发PhoneNumberFormatException{
用于(字符串mobileNumber:FailMobilEnumber){
获取164格式化的mobileNumber(mobileNumber,NO);
}
}

将原始电话号码存储在非操作列RAW_phone中,并将规范的E.164标准号码存储在phone列中(
“00”->“+”
”(“->”“
等)。这样,您就可以准备好检查列表和手动更正,并改进转换

可以想象的是,表中有两个phone列,第二个值是另一个扩展名
-203

如果国家代码转换失败或有其他可疑之处,最好不要填写strict字段。默认值是法国,或者当用户居住在比利时时是什么?
有人可能会说来源(位置)用户注册数量决定默认的国家代码。

谢谢你的详细回答,我真的很感激。总而言之,我理解你的例子,但这里有一个关键点是我真正的问题所在:国家代码。在你的例子中,它是挪威。但在我的情况下,它可以是任何东西!这真的令人不安。我有我的手机e(目前作为我的数据源)我看了看我的联系人列表。其中一些是我知道是法语的号码,但没有法国的国际代码
+33
。我该如何将这些号码格式化为E164?我的意思是,我的短信应用程序似乎做对了…当我发送/接收短信时,它会映射到你的短信应用程序。这根本不能回答问题。如果你拉控制键act list要在数据库中进行比较,您无法询问系统该号码所在的国家/地区,因为您无法访问该号码所指的每个人的电话。谢谢您的回答!这似乎是个好主意。由于用户可能会多次将我的应用程序与他的联系人数据库同步,因此我应该在修改/添加电话号码时进行处理/删除。到目前为止,纯粹从数据库的角度来看,我自己关心的是,我如何才能不插入重复的联系人条目,因为电话号码格式发生了变化,但基本上是同一个号码?因此,按照你的想法,我应该在将号码存储到
原始电话中时使用固定格式,以便进行比较。你认为呢这行得通吗?归根结底还是要比较一下。不过,还有一件事:如果提供的电话号码不是以
+
开头,我该如何格式化它呢