【问题标题】:Regex for Dutch telephone numbers荷兰电话号码的正则表达式
【发布时间】:2016-01-12 12:24:34
【问题描述】:

当谈到正则表达式时,我绝对不是最糟糕的,但这个让我很难过。

简而言之,这是我目前拥有的代码。

$aNumbers = array(
    '612345678',
    '546123465',
    '131234567',
    '+31(0)612345678'
);

foreach($aNumbers as $sNumber) {
    $aMatches = array();
    $sNumber = preg_replace('/(\(0\)|[^\d]+)/', '', $sNumber);

    preg_match('/(\d{1,2})?(\d{3})(\d{3})(\d{3})$/', $sNumber, $aMatches);

    var_dump($sNumber);
    var_dump($aMatches);
}

简单来说,就是想匹配特定格式的电话号码,保证统一显示。

+31(0)612345678
+31(0)131234567

两个剥离都没有 + 和 (0)。 部分切割:

31     6    123 456 78
Country Net Number
31     13   123 456 78
Country Net Number

现在,在某些情况下,+31(或 +1、+222)是可选的。 6 和 13 总是包含在内,但有趣的是,以下格式也是可能的:

31     546  123 456
Country Net Number

这甚至可以使用正则表达式吗?

【问题讨论】:

  • 是的,但如果我们现在不知道所有的净数字,则不是。
  • 您确定在第二个示例末尾有 8 吗?这似乎与您在部分削减之前写的数字不符。
  • 数据从何而来?理想情况下,您不必这样做。当用户填写表格时,呼叫代码和电话号码应该在他们自己的单独字段中,您所要做的就是对其进行清理。

标签: php regex


【解决方案1】:

我已经回答了其中一些类型的问题,我的策略是找出表达含义的格式或数字关系的某些部分,然后去掉其余部分。

One of my examples that parses non-NANP number formatting 在解析表达式中使用有效区号列表,并在存在时标识国家/地区代码。它提取国家代码、区号,然后是号码的其余部分。

或您所在的国家/地区,我假设 HansM 答案中的区域/网络/区域代码列表是正确的或易于替换,所以我猜想这种正则表达式的修改可能有用:

^[ -]*(\+31)?[ -]*[(0)]*[ -]*(7|43|32|45|33|49|39|31|47|34|46|41|90|44|351|353|358)[ -]*((?:\d[ -]*)+)

它将首先匹配国家代码(如果存在),并将其存储在反向引用 1 中,然后忽略单个零。然后它将匹配区域/网络/区域代码之一并将其存储在反向引用 2 中。然后它将获得任意数量的数字(一个或多个),混合破折号 (-) 和/或空格 (@ 987654326@) 并将它们存储到反向引用 3

在此之后,您可以解析第三个编号组的有效性或进一步重新格式化

我正在 Regex 101 上对其进行测试,但我可以使用可接受和不可接受输入的列表,以及在可接受时应如何重新格式化...

[编辑]

我使用了this list of city codes for the Netherlands 并因此修改了表达式:

^[ -]*(\+31)?[ -]*[(0)]*[ -]*([123457]0|23|24|26|35|45|71|73|570)[ -]*((?:\d[ -]*)+)

执行以下解析:

input                     (1)    (2)    (3) 
---------------------    ------ ------ ---------------
0707123456                       70     7123456
0267-123456                      26     7-123456
0407-12 34 56                    40     7-12 34 56
0570123456                       570    123456
07312345                         73     12345
+31(0)734423211           +31    73     4423211 

但我仍然不知道这是否对你有帮助

[编辑 2]

维基百科的内容似乎是a more comprehensive list of codes

010, 0111, 0113, 0114, 0115, 0117, 0118, 013, 015, 0161, 0162, 0164, 0165, 0166, 0167, 0168, 0172, 0174, 0180, 01681, 0182, 0188, 018, 0188, 018, 0 , 0187, 020, 0222, 0223, 0224, 0226, 0227, 0228, 0229, 023, 024, 0251, 0252, 0255, 026, 0294, 0297, 0299, 030, 0313, 0314, 017, 0314, 017, 0314, 017 , 0320, 0321, 033, 0341, 0342, 0343, 0344, 0345, 0346, 0347, 0348, 035, 036, 038, 040, 0411, 0412, 0413, 0416, 0418, 043, 450, 0418, 043, 75, 04 ,0481,0485,0486,0487,0488,0492,0493,0495,0497,0499,050,0511,0512,0513,0514,0515,0516,0517,0518,0519,0517,0518,0519,0521,0522,0523,0524,0525 , 0527, 0528, 0529, 053, 0541, 0543, 0544, 0545, 0546, 0547, 0548, 055, 0561, 0562, 0566, 0570, 0571, 0572, 0573, 0570, 059,70, 0570, 059,77 , 0593, 0594, 0595, 0596, 0597, 0598, 0599, 070, 071, 072, 073, 074, 075, 076, 077, 078, 079

可以像这样在代码选择部分使用(如果您希望它更容易阅读和更新):

10|111|113|114|115|117|118|13|15|161|162|164|165|166|167|168|172|174|180|181|182|183|184|186|187|20|222|223|224|226|227|228|229|23|24|251|252|255|26|294|297|299|30|313|314|315|316|317|318|320|321|33|341|342|343|344|345|346|347|348|35|36|38|40|411|412|413|416|418|43|45|46|475|478|481|485|486|487|488|492|493|495|497|499|50|511|512|513|514|515|516|517|518|519|521|522|523|524|525|527|528|529|53|541|543|544|545|546|547|548|55|561|562|566|570|571|572|573|575|577|578|58|591|592|593|594|595|596|597|598|599|70|71|72|73|74|75|76|77|78|79

或像这样(如果您希望对表达式进行更有效的评估):

1([035]|1[134578]|6[124-8]|7[24]|8[0-467])|2([0346]|2[2346-9]|5[125]|9[479])|3([03568]|1[34-8]|2[01]|4[1-8])|4([0356]|1[12368]|7[58]|8[15-8]|9[23579])|5([0358]|[19][1-9]|2[1-5789]|4[13-8]|6[126]|7[0-3578])|7[0-9]

【讨论】:

  • 我明天回去工作时会尝试将其合并,但您的解决方案似乎只是一个不错的解决方案。我会评价它回答它有效,谢谢!
  • @ReSpawN - 听起来不错 - 如果您需要帮助重新格式化其余号码,我也可以尝试提供帮助
【解决方案2】:

我使用了 nuget 包 libphonenumber-csharp。

这帮助我创建了一个(荷兰语)电话号码验证器,这是一个代码 sn-p,如果没有我的解决方案的其他部分,它将无法编译,但至少您可以了解如何处理这个问题。

  public override void Validate()
    {
        ValidationMessages = new Dictionary<string, string>();
        ErrorMessage = string.Empty;
        string phoneNumber;
        string countryCode = _defaultCountryCode;

        // If the phoneNumber is not required, it is allowed to be empty.
        // So in that case isValid gets defaultvalue true
        bool isValid = (!_isRequired);

        if (!string.IsNullOrEmpty(_phoneNumber))
        {
            var phoneUtil = PhoneNumberUtil.GetInstance();
            try
            {
                phoneNumber = PhoneNumbers.PhoneNumberUtil.Normalize(_phoneNumber);
                countryCode = PhoneNumberUtil2.GetRegionCode(phoneNumber, _defaultCountryCode);
                PhoneNumber oPhoneNumber = phoneUtil.Parse(phoneNumber, countryCode);
                var t1 = oPhoneNumber.NationalNumber;
                var t2 = oPhoneNumber.CountryCode;
                var formattedNo = phoneUtil.Format(oPhoneNumber, PhoneNumberFormat.E164);
                isValid = PhoneNumbers.PhoneNumberUtil.IsViablePhoneNumber(formattedNo);
            }
            catch (NumberParseException e)
            {
                var err = e.ToString();
                isValid = false;
            }
        }

        if ((isValid) && (!string.IsNullOrEmpty(_phoneNumber)))
        {
            Regex regexValidator = null;
            string regex;

            // Additional validations for Dutch phone numbers as LibPhoneNumber is to graceful as it comes to
            // thinking if a number is valid.
            switch (countryCode)
            {
                case "NL":

                    if (_phoneNumber.StartsWith("0800") || _phoneNumber.StartsWith("0900"))
                    {
                        // 0800/0900 numbers
                        regex = @"((0800|0900)(-| )?[0-9]{4}([0-9]{3})?$)";
                        regexValidator = new Regex(regex);
                        isValid = regexValidator.IsMatch(_phoneNumber);
                    }
                    else
                    {
                        string phoneNumberCheck = _phoneNumber.Replace("(", "").Replace(")", "").Replace("-", "").Replace(" ", "");

                        regex = @"^(0031|\+31|0)[1-9][0-9]{8}$";

                        regexValidator = new Regex(regex);
                        isValid = regexValidator.IsMatch(phoneNumberCheck);
                    }
                    break;
            }
        }
        if (!isValid)
        {
            ErrorMessage = string.Format(TextProvider.Get(TextProviderConstants.ValMsg_IsInAnIncorrectFormat_0),
                ColumnInfoProvider.GetLabel(_labelKey));

            ValidationMessages.Add(_messageKey, ErrorMessage);
        }
    }

基于 nuget 包 libphonenumber-csharp 构建的类 PhoneNumberUtil2 可能也很有用:

// Code start
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using PhoneNumbers;

namespace ProjectName.Logic.Miscellaneous
{
    public class PhoneNumberUtil2
    {
        /// <summary>
        /// Returns the alphanumeric country code for a normalized phonenumber. If a phonenumber does not contain 
        /// an international numeric country code, the default country code for the website is returned.
        /// This works for 17 countries: NL, GB, FR, DE, BE, AU, SE, NO, IT, TK, RU, CH, DK, IR, PT, ES, FI
        /// </summary>
        /// <param name="normalizedPhoneNumber"></param>
        /// <param name="defaultCountryCode"> </param>
        /// <returns></returns>
        public static string GetRegionCode(string normalizedPhoneNumber, string defaultCountryCode)
        {
            if (normalizedPhoneNumber.Length > 10)
            {
                var dict = new Dictionary<string, string>();
                dict.Add("7", "RU");
                dict.Add("43", "AT");
                dict.Add("32", "BE");
                dict.Add("45", "DK");
                dict.Add("33", "FR");
                dict.Add("49", "DE");
                dict.Add("39", "IT");
                dict.Add("31", "NL");
                dict.Add("47", "NO");
                dict.Add("34", "ES");
                dict.Add("46", "SE");
                dict.Add("41", "CH");
                dict.Add("90", "TR");
                dict.Add("44", "GB");
                dict.Add("351", "PT");
                dict.Add("353", "IE");
                dict.Add("358", "FI");

                // First check 3-digits International Calling Codes
                if (dict.ContainsKey(normalizedPhoneNumber.Substring(0, 3)))
                {
                    return dict[normalizedPhoneNumber.Substring(0, 3)];
                }

                // Then 2-digits International Calling Codes 
                if (dict.ContainsKey(normalizedPhoneNumber.Substring(0, 2)))
                {
                    return dict[normalizedPhoneNumber.Substring(0, 2)];
                }

                // And finally 1-digit International Calling Codes
                if (dict.ContainsKey(normalizedPhoneNumber.Substring(0, 1)))
                {
                    return dict[normalizedPhoneNumber.Substring(0, 1)];
                }
            }
            return defaultCountryCode;
        }

    }
}

【讨论】:

  • 虽然 OP 不是在寻找 .NET 解决方案,但深入研究库可能会为您提供解决此问题的正确正则表达式...
  • 你可能是对的,对不起。但确实,带有不同正则表达式的 switch 语句可能仍然有用。
  • 虽然我不能流利地键入 .NET,但我仍然可以像其他任何程序员一样阅读它——逻辑很好。不幸的是,这不是我真正需要的,但无论如何谢谢!
  • 对不起,我帮不了你,但最重要的是,我无法使用一个正则表达式来解决它,但需要在 switch 语句中使用两个正则表达式,并在使用正则检查数字之前进行一些预验证和格式化表达式。也许您可以在代码中遵循类似的逻辑。
猜你喜欢
  • 2011-02-26
  • 2012-04-08
  • 2013-07-27
  • 1970-01-01
  • 1970-01-01
  • 2017-09-23
  • 2014-02-15
相关资源
最近更新 更多