我得说实话,当我第一次看到一个正则表达式时,那是一次可怕的体验。它看起来就像一个奇怪的外星语言! 我心里想:"我花了几个月时间学习编程,现在还得学这个看似超级复杂的语言!?"
然而,当我坐下来真正学习正则表达式时,我发现它并不是很难,一旦你学会了语法。
为什么我甚至要费心学习正则表达式?
当你开始编码越来越多时,它确实在各种情况下都非常方便,不仅仅是为了验证电话号码和电子邮件地址。当从日志中提取数据、从 API 调用中提取混乱的 JSON 数据以及在许多其他情况下都非常有用。
我将教你如何用一行代码,用一个正则表达式来验证电话号码。不使用正则表达式验证电话号码就变成了一个讨厌的 leetcode 问题。 😧
验证电话号码为什么这么复杂?
假设你在网站上有一个表单用来收集电话号码以便向订阅者发送短信,他们提交电话号码的方式有很多种。
以下都是有效的号码:
202-515-5555
202 515 5555
(202)515 5555
1 202 515 5555
2025155555
1-202-515-5555
1202-515-5555
等
我没有列出更多有效的组合,但你明白了!验证每个组合变成一个恶心的编码问题。但如果你用正则表达式来验证就不是问题了! 😉
让我们从最简单的案例开始
首先验证202-515-5555
。正则表达式的基本思想是构建一个模式来匹配字符串。202-515-5555
中的模式是什么?
我们从 3 个数字开始,后面跟一个-
,再跟 3 个数字,然后是另一个-
,最后以 4 个数字结束。
这是匹配202-515-5555
的正则表达式模式看起来是这样的:
ruby
^\d{3}-\d{3}-\d{4}$
让我们来解释这个...
^
只是表示字符串的开始。在上面的正则表达式中,我们说明电话号码必须以\d{3}
开头,因为我们在\d{3}
前面加上了^
。
现在 \d
=> 代表单个数字 ,而**{3}
简单地意味着\d
确切地重复 3 次。所以^\d{3}
意味着我们的电话号码以 3 个数字开始。
现在让我们直接跳到结尾。$
表示字符串匹配的结束。\d{4}
意味着我们的电话号码必须以 4 个数字结束。 这有意义吗?
-
只是意味着电话号码在那个位置必须有一个破折号。
因此,现在让我们从左到右完整地读一遍整个正则表达式:
^\d{3}
=> 以 3 个数字开始-
=> 后跟一个破折号\d{3}
=> 再以 3 个数字为跟随-
=> 后跟一个破折号\d{4}$
=> 以 4 个数字结束
如有必要,请多次阅读上述部分,以确保在我们继续之前您已完全理解。
如果破折号是可选的,我该如何匹配电话号码?
好问题!我们如何同时匹配:202-515-5555
和2025155555
?
要使字符匹配变为可选的,只需在其后添加一个?
。
这是我们新改进的匹配看起来像这样:
ruby
^\d{3}-?\d{3}-?\d{4}$
-?
只是意味着-
是可选的:它可能存在,也可能不存在!
让我们再次完整地读一遍整个正则表达式:
^\d{3}
=> 以 3 个数字开始-?
=> 可选地后跟一个破折号\d{3}
=> 再以 3 个数字为跟随-?
=> 可选地后跟一个破折号\d{4}$
=> 以 4 个数字结束
如果有空格而不是破折号,又该如何匹配电话号码呢?
现在让我们来匹配:202-515-5555
、2025155555
和202 515 5555
。
不仅仅是有可选的-
,我们可以有-
或 `。我们如何表示这个?很简单,把`-`和
放进
[...]里,变成这样:
[ -]`。
我们的新正则表达式看起来是这样的:
ruby
^\d{3}[ -]?\d{3}[ -]?\d{4}$
现在它确实开始看起来很外星了!😅
让我们分解一下:
^\d{3}
=> 以 3 个数字开始[ -]?
=> 可选地 后跟一个空格或破折号\d{3}
=> 再以3个数字为跟随[ -]?
=> 可选地 后跟一个空格或破折号\d{4}$
=> 以 4 个数字结束
如何匹配电话号码开头的1
或1
或1-
基于我们所学的,你能解决这个问题吗?
一旦你意识到开头的1...
是可选的,就有点棘手了。
让我们一步一步来...
如果你想要电话号码以1
开头,我们在字符串匹配的开始添加^1
,对吗?现在我们想要在 1 后面可选地添加一个破折号或空格。幸运的是,我们已经知道如何做到这一点:[ -]?
。
结合这两个我们得到:^1[ -]?
把这个添加到我们之前的正则表达式中,我们得到:
ruby
^1[ -]?\d{3}[ -]?\d{3}[ -]?\d{4}$
你能感觉到这里有问题吗?上述正则表达式字符串匹配必须以1
开始,它不是可选的。 我们需要让1[ -]?
变成可选的。
我们怎么做呢? 由于我们在谈论多个元素:1
和[ -]?
,我们需要将整个内容放进(...)
中,创建一个组。然后在其后添加一个?
,以使整个组变成可选的!
我知道这有点多!这里是它的样子:
ruby
^(1[ -]?)?\d{3}[ -]?\d{3}[ -]?\d{4}$
让我们再次分解,现在有一个额外的步骤:
^(1[ -]?)?
=> 可选地 以 1 开始,后面 可选地 跟着一个 空格或破折号\d{3}
=> 以 3 个数字开始[ -]?
=> 可选地 后跟一个 空格或破折号\d{3}
=> 再以 3 个数字为跟随[ -]?
=> 可选地 后跟一个 空格或破折号\d{4}$
=> 以 4 个数字结束
🤯
如果你仍在阅读,恭喜你,你现在知道如何 思考 '正则表达式'了!
还有一个未解决的问题: 如何匹配像(202)515 5555
这样的电话号码。我将留给读者去解决(提示: 使用管道操作符:(...|...)
))。
把一切整合在一起来测试一个真实的电话号码字符串
现在让我们获取我们的正则表达式并将其转换成 JavaScript 中的正则表达式。为此,你只需要在它周围添加/.../
。然后使用一个称为test
的方法:
ini
const regex = /^(1[ -]?)?\d{3}[ -]?\d{3}[ -]?\d{4}$/;
const phoneNumber = '1202-515-5555';
// test返回'true'如果有匹配,如果没有则返回'false'
const match = regex.test(phoneNumber);