【问题标题】:RegEx: Uk Landlines, Mobile phone numbers正则表达式:英国固定电话、手机号码
【发布时间】:2010-09-08 15:49:39
【问题描述】:

我一直在努力寻找合适的解决方案:-

我需要一个匹配所有英国电话号码和手机的正则表达式。

到目前为止,这个似乎涵盖了大部分英国数字:

^0\d{2,4}[ -]{1}[\d]{3}[\d -]{1}[\d -]{1}[\d]{1,4}$

但是,手机号码不适用于此正则表达式或写在单个实心块中的电话号码,例如 01234567890。

谁能帮我创建所需的正则表达式?

【问题讨论】:

    标签: regex phone-number


    【解决方案1】:
      [\d -]{1}
    

    明显不正确:数字或空格或连字符。

      01000 123456
    

    01000 不是有效的英国区号。 123456 不是有效的本地号码。

    测试数据必须是实数区号和实数范围。

      ^\s*(?(020[7,8]{1})?[ ]?[1-9]{1}[0-9{2}[ ]?[0-9]{4})|(0[1-8]{1}[0-9]{3})?[ ]?[1-9]{1}[0-9]{2}[ ]?[0-9]{3})\s*|[0-9]+[ ]?[0-9]+$
    

    由于许多不同的原因,上述模式是垃圾。

    [7,8] 匹配 7 或逗号或 8。您不需要匹配逗号。

    伦敦数字也以 3 开头,而不仅仅是 7 或 8。

    伦敦 020 号码并不是唯一的 2+8 格式号码;另见 023、024、028 和 029。

    [1-9]{1} 简化为 [1-9]

    [ ]?简化为 \s?

    一次找到了初始0,为什么还要一遍又一遍地寻找呢?

    ^(0....|0....|0....|0....)$ 简化为 ^0(....|....|....| ....)$

    说真的。 ([1]|[2]|[3]|[7]){1} 在这里简化为 [1237]。

    英国电话号码使用多种格式:2+8、3+7、3+6、4+6、4+5、5+5、5+4。一些用户不知道哪种格式适用于哪个数字范围,并且可能在输入时使用了错误的格式。让他们这样做;你对 DIGITS 感兴趣。

    第 1 步:检查输入格式是否有效

    确保输入看起来像英国电话号码。接受各种拨号前缀,+44、011 44​​、00 44,带或不带括号、连字符或空格;或带有前导 0 的国家格式。让用户对数字的其余部分使用他们想要的任何格式:(020) 3555 7788 或 00 (44) 203 555 7788 或 02035-557-788,即使它是错误的格式那个特定的数字。不要担心不平衡的括号。输入的重要部分是确保它是正确的位数。标点和空格无关紧要。

      ^\(?(?:(?:0(?:0|11)\)?[\s-]?\(?|\+)44\)?[\s-]?\(?(?:0\)?[\s-]?\(?)?|0)(?:\d{5}\)?[\s-]?\d{4,5}|\d{4}\)?[\s-]?(?:\d{5}|\d{3}[\s-]?\d{3})|\d{3}\)?[\s-]?\d{3}[\s-]?\d{3,4}|\d{2}\)?[\s-]?\d{4}[\s-]?\d{4}|8(?:00[\s-]?11[\s-]?11|45[\s-]?46[\s-]?4\d))(?:(?:[\s-]?(?:x|ext\.?\s?|\#)\d+)?)$
    

    上述模式匹配可选的左括号,后跟 00 或 011 和可选的右括号,后跟可选的空格或连字符,然后是可选的左括号。或者,最初的左括号后面是文字 +,后面没有空格或连字符。前两个选项中的任何一个都紧跟 44 和可选的右括号,然后是可选的空格或连字符,然后是可选的括号中的可选 0,然后是可选的空格或连字符,然后是可选的左括号(国际格式)。或者,该模式匹配可选的初始左括号,后跟 0 中继代码(国家格式)。

    前一部分之后是 NDC(区号)和 2+8、3+7、3+6、4+6、4+5、5+5 或 5+4 格式的用户电话号码带或不带空格和/或连字符。这还包括在用户认为区号结束和本地用户号码开始的位置之后提供可选的右括号和/或可选的空格或连字符。该模式允许任何格式与任何 GB 编号一起使用。如果用户在输入时使用了错误的数字格式,则必须通过后面的逻辑更正显示格式。

    该模式以可选分机号码结尾,可选空格或连字符后跟 x、分机和可选句点,或 #,后跟分机号码数字。整个模式不会费心检查平衡括号,因为这些将在下一步中从数字中删除。

    此时,您并不关心数字是从 01 还是 07 开始还是其他什么。您不在乎它是否是有效的区号。后续步骤将处理这些问题。

    第 2 步:提取 NSN,以便更详细地检查其长度和范围

    使用上述模式检查输入看起来像 GB 电话号码后,下一步是提取 NSN 部分,以便更详细地检查其有效性,然后以正确的方式格式化适用的号码范围.

      ^\(?(?:(?:0(?:0|11)\)?[\s-]?\(?|\+)(44)\)?[\s-]?\(?(?:0\)?[\s-]?\(?)?|0)([1-9]\d{1,4}\)?[\s\d-]+)(?:((?:x|ext\.?\s?|\#)\d+)?)$
    

    使用上述模式从 $1 中提取 '44' 以知道使用了国际格式,否则如果 $1 为空则假定为国家格式。

    从 $3 中提取可选的分机号码详细信息并将其存储起来以备后用。

    从 $2 中提取 NSN(包括空格、连字符和括号)。

    第 3 步:验证 NSN

    从 $2 中删除空格、连字符和括号,并使用更多的 RegEx 模式来检查长度和范围并识别数字类型。

    这些模式会简单得多,因为它们不必处理各种拨号前缀或国家代码。

    匹配有效手机号码的模式因此很简单

      ^7([45789]\d{2}|624)\d{6}$
    

    保费率是

      ^9[018]\d{8}$
    

    每种号码类型将有许多其他模式:固定电话、业务费率、非地理、VoIP 等。

    通过将问题分解为几个步骤,可以允许非常广泛的输入格式,并且非常详细地检查 NSN 的数字范围和长度。

    第 4 步:存储号码

    在提取和验证 NSN 后,将数字与国家/地区代码和所有其他数字一起存储,不带空格或标点符号,例如442035557788.

    第 5 步:格式化数字以供显示

    另一组简单规则可用于格式化数字,并在开头添加必要的 +44 或 0。

    03开头的数字规则是

      ^44(3\d{2})(\d{3])(\d{4})$
    

    格式化为

      0$1 $2 $3 or as +44 $1 $2 $3
    

    对于以 02 开头的数字是

      ^44(2\d)(\d{4})(\d{4})$ 
    

    格式化为

      (0$1) $2 $3 or as +44 $1 $2 $3
    

    完整的列表很长。我可以将它全部复制并粘贴到这个线程中,但是随着时间的推移,很难在多个地方维护这些信息。目前可以在以下位置找到完整列表:http://aa-asterisk.org.uk/index.php/Regular_Expressions_for_Validating_and_Formatting_GB_Telephone_Numbers

    【讨论】:

    • 好答案,但您的链接现在似乎已损坏:-(
    【解决方案2】:

    考虑到人们有时会在随机的地方用空格写他们的数字,你最好忽略所有空格 - 你可以使用像这样简单的正则表达式:

    ^0(\d ?){10}$

    这匹配:

    • 01234567890
    • 01234 234567
    • 0121 3423 456
    • 01213 423456
    • 01000 123456

    但它也会匹配:

    • 01 2 3 4 5 6 7 8 9 0

    所以你可能不喜欢它,但它肯定更简单。

    【讨论】:

      【解决方案3】:

      这个正则表达式可以吗?

      //  using System.Text.RegularExpressions;
      
      /// <summary>
      ///  Regular expression built for C# on: Wed, Sep 8, 2010, 06:38:28 
      ///  Using Expresso Version: 3.0.2766, http://www.ultrapico.com
      ///  
      ///  A description of the regular expression:
      ///  
      ///  [1]: A numbered capture group. [\+44], zero or one repetitions
      ///      \+44
      ///          Literal +
      ///          44
      ///  [2]: A numbered capture group. [\s+], zero or one repetitions
      ///      Whitespace, one or more repetitions
      ///  [3]: A numbered capture group. [\(?]
      ///      Literal (, zero or one repetitions
      ///  [area_code]: A named capture group. [(\d{1,5}|\d{4}\s+?\d{1,2})]
      ///      [4]: A numbered capture group. [\d{1,5}|\d{4}\s+?\d{1,2}]
      ///          Select from 2 alternatives
      ///              Any digit, between 1 and 5 repetitions
      ///              \d{4}\s+?\d{1,2}
      ///                  Any digit, exactly 4 repetitions
      ///                  Whitespace, one or more repetitions, as few as possible
      ///                  Any digit, between 1 and 2 repetitions
      ///  [5]: A numbered capture group. [\)?]
      ///      Literal ), zero or one repetitions
      ///  [6]: A numbered capture group. [\s+|-], zero or one repetitions
      ///      Select from 2 alternatives
      ///          Whitespace, one or more repetitions
      ///          -
      ///  [tel_no]: A named capture group. [(\d{1,4}(\s+|-)?\d{1,4}|(\d{6}))]
      ///      [7]: A numbered capture group. [\d{1,4}(\s+|-)?\d{1,4}|(\d{6})]
      ///          Select from 2 alternatives
      ///              \d{1,4}(\s+|-)?\d{1,4}
      ///                  Any digit, between 1 and 4 repetitions
      ///                  [8]: A numbered capture group. [\s+|-], zero or one repetitions
      ///                      Select from 2 alternatives
      ///                          Whitespace, one or more repetitions
      ///                          -
      ///                  Any digit, between 1 and 4 repetitions
      ///              [9]: A numbered capture group. [\d{6}]
      ///                  Any digit, exactly 6 repetitions
      ///  
      ///
      /// </summary>
      public Regex MyRegex = new Regex(
            "(\\+44)?\r\n(\\s+)?\r\n(\\(?)\r\n(?<area_code>(\\d{1,5}|\\d{4}\\s+"+
            "?\\d{1,2}))(\\)?)\r\n(\\s+|-)?\r\n(?<tel_no>\r\n(\\d{1,4}\r\n(\\s+|-"+
            ")?\\d{1,4}\r\n|(\\d{6})\r\n))",
          RegexOptions.IgnoreCase
          | RegexOptions.Singleline
          | RegexOptions.ExplicitCapture
          | RegexOptions.CultureInvariant
          | RegexOptions.IgnorePatternWhitespace
          | RegexOptions.Compiled
          );
      
      
      
      //// Replace the matched text in the InputText using the replacement pattern
      // string result = MyRegex.Replace(InputText,MyRegexReplace);
      
      //// Split the InputText wherever the regex matches
      // string[] results = MyRegex.Split(InputText);
      
      //// Capture the first Match, if any, in the InputText
      // Match m = MyRegex.Match(InputText);
      
      //// Capture all Matches in the InputText
      // MatchCollection ms = MyRegex.Matches(InputText);
      
      //// Test to see if there is a match in the InputText
      // bool IsMatch = MyRegex.IsMatch(InputText);
      
      //// Get the names of all the named and numbered capture groups
      // string[] GroupNames = MyRegex.GetGroupNames();
      
      //// Get the numbers of all the named and numbered capture groups
      // int[] GroupNumbers = MyRegex.GetGroupNumbers();
      

      注意空格和破折号是如何可选的,并且可以成为其中的一部分。它现在被分为两个捕获组,称为area_codetel_no,以便将其分解并更容易提取。

      【讨论】:

      • 我试过那个没有用:(标准的 01000 123456 失败了。到目前为止,我最接近完美的是:^\s*(?(020[7,8]{1 })?[ ]?[1-9]{1}[0-9{2}[ ]?[0-9]{4})|(0[1-8]{1}[0-9]{ 3})?[ ]?[1-9]{1}[0-9]{2}[ ]?[0-9]{3})\s*|[0-9]+[ ]?[0 -9]+$ 但它相当厚实
      • 我以前错误地实现了它,不幸的是我必须在哪里实现这个正则表达式并不理想。但是,我有时间重构整个验证,这种方法确实解决了我的大部分问题,谢谢
      【解决方案4】:

      去掉所有空格和非数字字符,然后进行测试。这将是 musch ,比尝试考虑括号、空格等所有可能的选项要容易得多。 请尝试以下操作:

      @"^(([0]{1})|([\+][4]{2}))([1]|[2]|[3]|[7]){1}\d{8,9}$"
      

      0+44(国际)开头 - 我相信您可以根据需要添加 0044
      然后它有一个1237
      然后它有 8 位或 9 位数字。

      如果您想变得更聪明,以下可能是有用的参考:http://en.wikipedia.org/wiki/Telephone_numbers_in_the_United_Kingdom

      【讨论】:

      • +1,但不能认真对待 [0]{1}[4]{2}... oO 另外,分组太多了。
      • 感谢您的回复,不幸的是我无法编辑 c# 以从字符串中去除空格。
      【解决方案5】:

      这不是一个单一的正则表达式,而是来自Braemoor Software 的示例代码,易于遵循且相当全面。

      JS 版本可能是最容易阅读的。它去掉空格和连字符(我意识到你说过你不能这样做),然后应用一些正则表达式检查和负正则表达式检查。

      【讨论】:

        【解决方案6】:

        首先去除非数字,除了作为第一个字符的 +。

        (Javascript)

        var tel=document.getElementById("tel").value;
        tel.substr(0,1).replace(/[^+0-9]/g,'')+tel.substr(1).replace(/[^0-9]/g,'')
        

        除非代码为 +44(英国),否则下面的正则表达式允许在国际指示符 + 之后使用 7 到 15 位(国际电联最大值)之间的任意组合。否则,如果字符串以 +44、+440 或 0 开头,后跟 2 或 7,然后是任意数字中的 9,或者后跟 1,然后是除 0 之外的任何数字,然后是任意数字中的 7 或 8数字。 (所以 0203 有效,0703 有效但 0103 无效)。目前没有 025(或伦敦 0205)这样的代码,但这些代码有一天会被分配。

        /(^\+(?!44)[0-9]{7,15}$)|(^(\+440?|0)(([27][0-9]{9}$)|(1[1-9][0-9]{7,8}$)))/
        

        其主要目的是识别非公司号码的正确起始数字,然后是正确的数字位数。如果用户的本地号码是 5、6、7 或 8 位数字,则不推断。它没有强制禁止用户号码中的初始“1”或“0”,关于这些旧规则是否仍在执行,我找不到任何信息。英国电话规则不适用于来自英国以外的格式正确的国际电话号码。

        【讨论】:

          【解决方案7】:

          在长时间搜索涵盖英国案例的有效正则表达式后,我发现验证英国电话号码的最佳方法(如果您使用客户端 JavaScript)是使用 libphonenumber-js 以及自定义配置来减少捆绑包大小:

          如果您使用的是 NodeJS,请运行以下命令生成英国元数据:

          npx libphonenumber-metadata-generator metadata.custom.json --countries GB --extended
          

          然后导入元数据并使用libphonenumber-js/core:

          import { isValidPhoneNumber } from "libphonenumber-js/core";
          import data from "./metadata.custom.json";
          
          isValidPhoneNumber("01234567890", "GB", data);
          

          CodeSandbox Example

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2013-04-30
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2019-05-30
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多