使用正则表达式格式化电话号码

13

可能是重复问题:
用于电话号码验证的全面正则表达式

我有一个未格式化的电话号码(保证为10位数字)和一个未格式化的分机号码(可以为空、空格或任意数量的数字)。 我需要将它们组合成一个“友好”的字符串。 我打算将它们连接起来,然后使用 Regex.Replace 格式化连接。 这是我正在使用的单元测试,以尝试在插入一个正则表达式之前尝试各种正则表达式:

    [Test, Ignore("Sandbox, does not test production code")]
    public void TestPhoneRegex()
    {
        string number = "1234567890";
        string extension = "";

        var formattedContactNumber =
            Regex.Replace("{0} x{1}".FormatWith(number, extension),
                          @"^(\d{3})[ -]?(\d{3})[ -]?(\d{4})( x\d+)?",
                          @"$1-$2-$3$4");

        Debug.WriteLine("{0} x{1}".FormatWith(number, extension));
        Debug.WriteLine(formattedContactNumber);

        Assert.AreEqual("123-456-7890", formattedContactNumber);
    }

期望的格式化字符串是不带"x"和扩展号码的电话号码。然而,最后一个捕获组匹配了带或不带数字的"x",所以我得到的结果是"123-456-7890 x",而不是"123-456-7890"。这是发布前需要解决的最后一点开发问题。能否提供帮助?


从组中删除x?(x \d+)?变成[\sx]*?(\d+)? - Brad Christie
当你写“exception”时,你是指“extension”,对吗? - Mark Byers
1
为什么你要在连接后再格式化它们? - Oliver Charlesworth
1
我讨厌这些电话号码格式化的东西,因为它们总是假定每个人的号码都有相同数量的数字(不是!)以及相同的模式(不是!) - Donal Fellows
1
@Donal,非常正确啊?也许他正在开发一个只在北美洲运行的应用程序?这里的号码都保证是10位数(不包括国家代码和包括区号)。 - John McDonald
显示剩余3条评论
3个回答

13

我喜欢正则表达式,不要误会,但这似乎不是一个适用的领域。你所做的只是给10个数字的字符串添加破折号,然后加上一个可选的"x"和分机号码。简单才是更好的选择。

public static String beautifyPhoneNumber(String number, String extension)
{
    String beautifulNumber = number.Substring(0, 3) + "-" +
                             number.Substring(3, 3) + "-" +
                             number.Substring(6, 4);
    if (!String.IsNullOrEmpty(extension))
    {
        beautifulNumber += " x" + extension;
    }
    return beautifulNumber;
}

4

您的正则表达式无法匹配x,因此它不会被替换掉。请尝试使用以下正则表达式:

@"^(\d{3})[ -]?(\d{3})[ -]?(\d{4}) x(\d*)

在新的正则表达式中,x不再是可选项- 根据您的代码,它将始终存在(如果您确实希望它是可选的,则可以使用?x?(\d*))。另外,我们正在使用\d*,因此请确保即使为空,最后一组也始终匹配。

1
这就是问题所在:因为字符串的结尾没有匹配上,所以在替换时它仍然保持不变。我用了稍微不同的方法来解决它,添加了一个未被捕获的 .*$ 来指示我想要匹配(和替换)整个字符串,无论我是否捕获了可选部分。 - KeithS

3

也许这不是你问题的直接答案,但可能会有所帮助...我们使用这种模式:

public const string NorthAmericanPhonePattern = @"^(\+?(?<NatCode>1)\s*[-\/\.]?)?(\((?<AreaCode>\d{3})\)|(?<AreaCode>\d{3}))\s*[-\/\.]?\s*(?<Number1>\d{3})\s*[-\/\.]?\s*(?<Number2>\d{4})\s*(([xX]|[eE][xX][tT])\.?\s*(?<Ext>\d+))*$";

然后使用以下方式重新格式化:

private static string PhoneNumberMatchEvaluator(Match match)
{
    // Format to north american style phone numbers "0 (000) 000-0000"
    //                                          OR  "(000) 000-0000"
    Debug.Assert(match.Success);
    if (match.Groups["NatCode"].Success)
    {
        return match.Result("${NatCode} (${AreaCode}) ${Number1}-${Number2}");
    }
    else
    {
        return match.Result("(${AreaCode}) ${Number1}-${Number2}");
    }
}

private static string FormatPhoneNumber(string phoneNumber)
{
    var regex = new Regex(NorthAmericanPhonePattern, RegexOptions.IgnoreCase);
    return regex.Replace(phoneNumber, new MatchEvaluator(PhoneNumberMatchEvaluator));
}

注意:在我们的情况下,我们已经包括了国家代码,如果他们已经包括了,你可以轻松地将其去掉。我们也没有将扩展名包含在其中 - 如果我们发现它,我们会将其移出并放入不同的字段中。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接