【问题标题】:Regular Expression to reformat a US phone number in Javascript在 Javascript 中重新格式化美国电话号码的正则表达式
【发布时间】:2021-04-22 01:59:14
【问题描述】:

我正在寻找重新格式化(替换,而不是验证 - 有许多用于验证的参考)电话号码以在 Javascript 中显示。以下是部分数据的示例:

  • 123 4567890
  • (123) 456-7890
  • (123)456-7890
  • 123 456 7890
  • 123.456.7890
  • (空白/空)
  • 1234567890

有没有一种简单的方法可以使用正则表达式来做到这一点?我正在寻找最好的方法来做到这一点。有没有更好的办法?

我想将号码重新格式化为以下格式:(123) 456-7890

【问题讨论】:

  • 你的目标格式是哪一种?
  • 这个:(123) 456-7890
  • 我会说只是去掉所有非数字字符然后取三个子字符串。
  • @Wiseguy 请将其作为答案发布(带有示例),因为这确实是 OP 应该做的。
  • 您还需要指定每种接受的格式如何映射到目标格式,如果输入为空,则根本不明显。除非您愿意使用额外的条件来消除这种情况。

标签: javascript regex


【解决方案1】:

假设您想要格式“(123) 456-7890”:

function formatPhoneNumber(phoneNumberString) {
  var cleaned = ('' + phoneNumberString).replace(/\D/g, '');
  var match = cleaned.match(/^(\d{3})(\d{3})(\d{4})$/);
  if (match) {
    return '(' + match[1] + ') ' + match[2] + '-' + match[3];
  }
  return null;
}

这是一个允许可选+1 国际代码的版本:

function formatPhoneNumber(phoneNumberString) {
  var cleaned = ('' + phoneNumberString).replace(/\D/g, '');
  var match = cleaned.match(/^(1|)?(\d{3})(\d{3})(\d{4})$/);
  if (match) {
    var intlCode = (match[1] ? '+1 ' : '');
    return [intlCode, '(', match[2], ') ', match[3], '-', match[4]].join('');
  }
  return null;
}
formatPhoneNumber('+12345678900') // => "+1 (234) 567-8900"
formatPhoneNumber('2345678900')   // => "(234) 567-8900"

【讨论】:

  • 完美;谢谢你!不过我在添加这个功能后把return (!m) ? null改成了return (!m) ? ""
  • 关于如何解决问题的很好的一课。我试图思考如何匹配所有可能的情况——你消除不相关的,看看是否有匹配。非常好。
  • 仅供参考,这不适用于像 +1555-555-5555 这样的数字
  • '' + phoneNumberStringphoneNumberString 相同...已经是字符串了。
  • @AdamZerner 是的,但其他国家/地区的电话号码并非都是十位数,因此此处的格式不适用于国际。
【解决方案2】:

可能的解决方案:

function normalize(phone) {
    //normalize string and remove all unnecessary characters
    phone = phone.replace(/[^\d]/g, "");

    //check if number length equals to 10
    if (phone.length == 10) {
        //reformat and return phone number
        return phone.replace(/(\d{3})(\d{3})(\d{4})/, "($1) $2-$3");
    }

    return null;
}

var phone = '(123)4567890';
phone = normalize(phone); //(123) 456-7890

【讨论】:

    【解决方案3】:

    var x = '301.474.4062';
        
    x = x.replace(/\D+/g, '')
         .replace(/(\d{3})(\d{3})(\d{4})/, '($1) $2-$3');
    
    alert(x);

    【讨论】:

    • 谢谢肖恩,我喜欢你简短的内联解决方案。
    • 谢谢!例如,我将其更改为x = x.replace(/[^\d]+/g, '') .replace(/(\d{1})(\d{3})(\d{3})(\d{4})/, '+$1 ($2) $3-$4');,以便在电话号码前添加“+1”
    • 谢谢!这正是我需要的
    【解决方案4】:

    这个答案借用了 maerics 的答案。它的主要区别在于它接受部分输入的电话号码并格式化已输入的部分。

    phone = value.replace(/\D/g, '');
    const match = phone.match(/^(\d{1,3})(\d{0,3})(\d{0,4})$/);
    if (match) {
      phone = `${match[1]}${match[2] ? ' ' : ''}${match[2]}${match[3] ? '-' : ''}${match[3]}`;
    }
    return phone
    

    【讨论】:

    • 这在您键入时起作用,从源海报中添加所需的格式。经过 1.5 小时的搜索,我很高兴我尝试了这个!
    • 如果有帮助,我在区号周围添加了括号:(${match[1]}${match[2] ? ') ' : ''}${match[2]}${match[3] ? '-' : ''}${match[3]}
    • 实际上问题是你不能在'-'或中间字符串的空格上退格。当用户退格时,您需要防止重新格式化(例如newstring.length < oldstring.length 或跟踪光标位置并确定用户何时刚刚退格超过这些分隔符,例如if (cursorPosition === 4 && numericString.length > 3)
    • 在我的反应代码中,我通过在内部仅存储输入的数字然后格式化放置在该字段中的内容来解决这个问题。所以退格会删除实际值中的前一个字符,而不是显示的值。
    【解决方案5】:

    我正在使用这个函数来格式化美国数字。

    function formatUsPhone(phone) {
    
        var phoneTest = new RegExp(/^((\+1)|1)? ?\(?(\d{3})\)?[ .-]?(\d{3})[ .-]?(\d{4})( ?(ext\.? ?|x)(\d*))?$/);
    
        phone = phone.trim();
        var results = phoneTest.exec(phone);
        if (results !== null && results.length > 8) {
    
            return "(" + results[3] + ") " + results[4] + "-" + results[5] + (typeof results[8] !== "undefined" ? " x" + results[8] : "");
    
        }
        else {
             return phone;
        }
    }
    

    它接受几乎所有可以想象的书写美国电话号码的方式。结果被格式化为标准格式 (987) 654-3210 x123

    【讨论】:

      【解决方案6】:

      向后思考

      只取最后一位(最多 10 位)忽略第一个“1”。

      function formatUSNumber(entry = '') {
        const match = entry
          .replace(/\D+/g, '').replace(/^1/, '')
          .match(/([^\d]*\d[^\d]*){1,10}$/)[0]
        const part1 = match.length > 2 ? `(${match.substring(0,3)})` : match
        const part2 = match.length > 3 ? ` ${match.substring(3, 6)}` : ''
        const part3 = match.length > 6 ? `-${match.substring(6, 10)}` : ''    
        return `${part1}${part2}${part3}`
      }
      

      输入/输出示例

      formatUSNumber('+1333')
      // (333)
      
      formatUSNumber('333')
      // (333)
      
      formatUSNumber('333444')
      // (333) 444
      
      formatUSNumber('3334445555')
      // (333) 444-5555
      

      【讨论】:

        【解决方案7】:

        根据 David Baucum 的回答 - 这是一个尝试改进“在您键入时”自动替换的版本,例如在 React onChange 事件处理程序中:

        function formatPhoneNumber(phoneNumber) {
          const cleanNum = phoneNumber.toString().replace(/\D/g, '');
          const match = cleanNum.match(/^(\d{3})(\d{0,3})(\d{0,4})$/);
          if (match) {
            return '(' + match[1] + ') ' + (match[2] ? match[2] + "-" : "") + match[3];
          }
          return cleanNum;
        }
        
        //...
        
        onChange={e => setPhoneNum(formatPhoneNumber(e.target.value))}
        

        只要有 3 个数字,它就会插入 (###),然后它会一直跟随 RegEx,直到看起来像这样 (###) ###-####

        【讨论】:

          【解决方案8】:

          2021

          libphonenumber-js

          例子

          import parsePhoneNumber from 'libphonenumber-js'
          
          const phoneNumber = parsePhoneNumber('+12133734253')
          
          phoneNumber.formatInternational() === '+1 213 373 4253'
          phoneNumber.formatNational() === '(213) 373-4253'
          phoneNumber.getURI() === 'tel:+12133734253'
          

          【讨论】:

          • 这看起来确实是一个非常实用的库!不过 145kB,如果您只是在寻找格式化数字的东西,这有点重。只是其他人要记住的事情。
          【解决方案9】:

          我已扩展 David Baucum's answer 以包括对长度最多为 4 位的扩展的支持。它还包括原始问题中要求的括号。当您在字段中键入时,此格式将起作用。

          phone = phone.replace(/\D/g, '');
          const match = phone.match(/^(\d{1,3})(\d{0,3})(\d{0,4})(\d{0,4})$/);
          if (match) {
              phone = `(${match[1]}${match[2] ? ') ' : ''}${match[2]}${match[3] ? '-' : ''}${match[3]}${match[4] ? ' x' : ''}${match[4]}`;
          }
          return phone;
          

          【讨论】:

            【解决方案10】:
            var numbers = "(123) 456-7890".replace(/[^\d]/g, ""); //This strips all characters that aren't digits
            if (numbers.length != 10) //wrong format
                //handle error
            var phone = "(" + numbers.substr(0, 3) + ") " + numbers.substr(3, 3) + "-" + numbers.substr(6); //Create format with substrings
            

            【讨论】:

              【解决方案11】:

              这是一个同时接受电话号码和带分机号码的电话号码。

              function phoneNumber(tel) {
              var toString = String(tel),
                  phoneNumber = toString.replace(/[^0-9]/g, ""),
                  countArrayStr = phoneNumber.split(""),
                  numberVar = countArrayStr.length,
                  closeStr = countArrayStr.join("");
              if (numberVar == 10) {
                  var phone = closeStr.replace(/(\d{3})(\d{3})(\d{4})/, "$1.$2.$3"); // Change number symbols here for numbers 10 digits in length. Just change the periods to what ever is needed.
              } else if (numberVar > 10) {
                  var howMany = closeStr.length,
                      subtract = (10 - howMany),
                      phoneBeginning = closeStr.slice(0, subtract),
                      phoneExtention = closeStr.slice(subtract),
                      disX = "x", // Change the extension symbol here
                      phoneBeginningReplace = phoneBeginning.replace(/(\d{3})(\d{3})(\d{4})/, "$1.$2.$3"), // Change number symbols here for numbers greater than 10 digits in length. Just change the periods and to what ever is needed. 
                      array = [phoneBeginningReplace, disX, phoneExtention],
                      afterarray = array.splice(1, 0, " "),
                      phone = array.join("");
              
              } else {
                  var phone = "invalid number US number";
              }
              return phone;
              }
              
              phoneNumber("1234567891"); // Your phone number here
              

              【讨论】:

                【解决方案12】:

                当用户尝试在分隔符上退格时,几乎所有这些都会出现问题,特别是从字符串的中间。

                这是一个处理该问题的 jquery 解决方案,并确保在您编辑时光标停留在正确的位置:

                //format text input as phone number (nnn) nnn-nnnn
                $('.myPhoneField').on('input', function (e){
                    var $phoneField = e.target;
                    var cursorPosition = $phoneField.selectionStart;
                    var numericString = $phoneField.value.replace(/\D/g, '').substring(0, 10);
                
                    // let user backspace over the '-'
                    if (cursorPosition === 9 && numericString.length > 6) return;
                
                    // let user backspace over the ') '
                    if (cursorPosition === 5 && numericString.length > 3) return;
                    if (cursorPosition === 4 && numericString.length > 3) return;
                
                    var match = numericString.match(/^(\d{1,3})(\d{0,3})(\d{0,4})$/);
                    if (match) {
                        var newVal = '(' + match[1];
                        newVal += match[2] ? ') ' + match[2] : '';
                        newVal += match[3] ? '-' + match[3] : '';
                
                        // to help us put the cursor back in the right place
                        var delta = newVal.length - Math.min($phoneField.value.length, 14);      
                        $phoneField.value = newVal;
                        $phoneField.selectionEnd = cursorPosition + delta;
                    } else {
                        $phoneField.value = '';        
                    }
                })
                

                【讨论】:

                • 这个问题和其他以前的答案不是关于“当用户打字时”。只是接受输入并给出格式化的输出。
                【解决方案13】:

                美国电话号码

                /^\(?(\d{3})\)?[- ]?(\d{3})[- ]?(\d{4})$/
                

                让我们把这个正则表达式分成更小的片段,以便于理解。

                • /^\(?:表示电话号码可以以可选的(开头。
                • (\d{3}):在可选的( 之后必须有3 个数字。如果电话号码没有(,则必须以 3 位数字开头。例如。 (308308
                • \)?:表示电话号码的前 3 位后面可以有一个可选的)
                • [- ]?:接下来,电话号码可以在 ) 之后或前 3 位数字之后有一个可选的连字符 (-)。
                • (\d{3}):那肯定还有3个数字。例如 (308)-135308-135308135
                • [- ]?:在第二组 3 位数字之后,电话号码可以有另一个可选的连字符 (-)。例如 (308)-135-308-135-308135-
                • (\d{4})$/:最后,电话号码必须以四位数字结尾。例如(308)-135-7895308-135-7895308135-78953081357895

                  参考:

                http://www.zparacha.com/phone_number_regex/

                【讨论】:

                • 从其他网站复制内容然后甚至不发布链接是非常糟糕的行为:zparacha.com/phone_number_regex
                • 对不起,我不知道我们必须发布链接。我认为我们必须对发布的查询提供答案。
                • 永远不会让别人的作品看起来像你自己的作品。下次请记住,发布链接并没有错,但复制(尤其是不提供链接)则不然。而且您始终可以选择编辑您的答案。
                • 投了反对票,因为作者没有按照作者的要求回答如何替换电话号码。
                • 赞成,因为作者现在提供了链接,这个解决方案有明确的解释,这个解决方案对我有用。
                【解决方案14】:

                您可以使用此函数检查有效的电话号码并对其进行规范化:

                let formatPhone = (dirtyNumber) => {
                 return dirtyNumber.replace(/\D+/g, '').replace(/(\d{3})(\d{3})(\d{4})/, '($1) $2-$3');
                }
                
                let isPhone = (phone) => {
                   //normalize string and remove all unnecessary characters
                   phone = phone.replace(/\D+/g, '');
                   return phone.length == 10? true : false;
                }
                

                【讨论】:

                  【解决方案15】:

                  上述解决方案更胜一筹,尤其是在使用 Java 时,遇到更多超过 10 位的号码,例如国际代码前缀或附加分机号码。这个解决方案是基本的(我是正则表达式世界的初学者),并且在设计时考虑到了美国电话号码,并且仅适用于只有 10 个可能带有一些格式字符的数字的字符串,或者可能根本没有格式字符(只有 10 个数字)。因此,我仅将这种解决方案推荐用于半自动应用程序。我个人更喜欢将数字存储为仅 10 个数字而没有格式化字符,但也希望能够将电话号码转换或清理为普通人和应用程序/电话可以随意识别的标准格式。

                  我发现这篇文章是为了寻找可以与具有 PCRE 正则表达式功能(但没有 java 功能)的文本清理器应用程序一起使用的东西。我将在这里为那些可以使用简单的纯正则表达式解决方案的人发布这个,该解决方案可以在各种文本编辑器、清理器、扩展器甚至某些剪贴板管理器中工作。我个人使用 Sublime 和 TextSoap。此解决方案是为 Text Soap 设计的,因为它位于菜单栏中,并提供了一个下拉菜单,您可以在其中触发对光标选择的内容或剪贴板中的内容进行文本操作。

                  我的方法本质上是两个替换/搜索和替换正则表达式。每个替换搜索和替换都涉及两个正则表达式,一个用于搜索,一个用于替换。

                  替换/搜索和替换 #1

                  • 第一次替换/搜索和替换将非数字数字从原本为 10 位的数字剥离为 10 位字符串。

                  第一次替换/搜索正则表达式:\D

                  • 此搜索字符串匹配所有数字的字符。

                  First Substitution/ Replace 正则表达式:“”(什么都没有,甚至没有空格)

                  • 将替代字段完全留空,不应存在空格,包括空格。这将导致所有匹配的非数字字符被删除。在此操作之前,您应该输入 10 位数字 + 格式化字符,然后输出 10 位无格式化字符。

                  替换/搜索和替换 #2

                  • 操作的第二个替换/搜索和替换搜索部分捕获区号$1的组,第二组三个数字$2的捕获组,最后一个捕获组最后一组四个数字$3。操作的 substitute 部分的正则表达式在捕获的数字组之间插入美国电话号码格式。

                  第二次替换/ 搜索 正则表达式:(\d{3})(\d{3})(\d{4})

                  第二次替换/ 替换 正则表达式:\($1\) $2\-$3

                  • 反斜杠 \ 转义特殊字符 () (-,因为我们将它们插入到捕获组中捕获的数字之间 $1、@ 987654333@, & $3 用于美国电话号码格式化。

                  • 在 TextSoap 中,我创建了一个自定义清理器,其中包括两个替换操作操作,因此在实践中感觉与执行脚本相同。我确信这个解决方案可以改进,但我预计复杂性会上升很多。如果有人想添加此解决方案,我们欢迎将此解决方案的改进版本作为学习体验。

                  【讨论】:

                    猜你喜欢
                    • 2012-01-11
                    • 1970-01-01
                    • 2015-11-22
                    • 2020-05-02
                    • 1970-01-01
                    • 1970-01-01
                    • 2018-01-23
                    • 1970-01-01
                    • 1970-01-01
                    相关资源
                    最近更新 更多