5分钟搞懂 —— 正则表达式 (by 令爷)
引言
正则表达式是一种强大的文本匹配和处理工具。它就像是一个神奇的模式识别系统,能帮助我们在文本中查找、匹配和替换特定的字符串。无论是验证用户输入、处理文本文件,还是进行数据分析,正则表达式都能大显身手。
让我们通过一个简单的例子开始。假设你需要在一篇文章中找出所有的电话号码,你会怎么做?如果手动查找,这将是一项耗时的工作。但使用正则表达式,我们可以用一行代码就能完成这个任务。
1. 基础匹配
在深入学习正则表达式之前,我们先从最简单的开始 - 普通字符的匹配。
当我们在文本中查找一个确切的词时,可以直接使用这个词作为正则表达式。比如:
- 要查找文本中的"hello",直接使用正则表达式
hello
- 要查找"2024",直接使用
2024
这就是最基本的正则表达式。它会精确匹配你指定的字符。
2. 元字符
元字符是正则表达式的基本构建块,用于定义匹配模式。以下是几个常用的元字符及其功能:
元字符 | 说明 | 记忆提示 |
---|---|---|
. |
匹配除换行符以外的任意字符 | 小圆点,代表多种字符,但不包括换行符 |
\w |
匹配字母、数字、下划线或汉字 | “word”的缩写,代表“单词字符” |
\s |
匹配任意的空白符 | “space”的缩写,匹配空白字符 |
\b |
匹配单词边界 | “bound”的缩写,表示单词的边界 |
\d |
匹配数字 | “digit”的缩写,仅匹配数字 |
^ |
匹配字符串的开始 | 表示字符串的起始位置 |
$ |
匹配字符串的结束 | 表示字符串的结束位置 |
有了元字符之后,我们就可以利用这些元字符来写一些简单的正则表达式了:
- 匹配有
abc
开头的字符串:\babc
或者^abc
- 匹配 8 位数字的 QQ 号码:
^\d\d\d\d\d\d\d\d$
- 匹配 1 开头 11 位数字的手机号码:
^1\d\d\d\d\d\d\d\d\d\d$
上述正则表达式^1\d\d\d\d\d\d\d\d\d\d$
虽然功能明确,但在可读性和简洁性方面存在不足。为了提升表达式的简洁性和可维护性,可以通过量词进行简化。例如,可以使用 重复限定符 {n}
语法来指定重复次数,从而将表达式简化为 ^1\d{10}$
。这种写法不仅更加简洁,而且更易于理解和维护。
3. 重复限定符
下面我们来看一些限定符,拓展部分增加了示例说明和使用场景:
语法 | 说明 | 拓展 |
---|---|---|
* |
重复零次或更多次 | 示例:a* 匹配字符串中出现零次或多次的字符 a ,如匹配空字符串、a 、aa 、aaa 等。常用于匹配可选的字符或字符序列。例如,在正则表达式中用于匹配文件名中的可选扩展名,如 file.* 可匹配 file.txt 、file.jpg 等。 |
+ |
重复一次或更多次 | 示例:a+ 匹配字符串中至少出现一次的字符 a ,如匹配 a 、aa 、aaa 等,但不匹配空字符串。常用于匹配必须存在的字符或字符序列。例如,在匹配电话号码时,[0-9]+ 可以匹配任意长度的数字序列。 |
? |
重复零次或一次 | 示例:a? 匹配字符串中出现零次或一次的字符 a ,如匹配空字符串或 a 。常用于匹配可选的字符。例如,在匹配日期格式时,(\d{1,2})-(\d{1,2})-(\d{2,4})? 可以匹配 01-01 或 01-01-2024 。 |
{n} |
重复 n 次 | 示例:a{3} 匹配字符串中恰好出现 3 次的字符 a ,如匹配 aaa 。常用于精确匹配固定数量的字符。例如,在匹配固定长度的验证码时,[0-9]{6} 可以匹配 6 位数字验证码。 |
{n,} |
重复 n 次或更多次 | 示例:a{3,} 匹配字符串中至少出现 3 次的字符 a ,如匹配 aaa 、aaaa 等。常用于匹配至少出现 n 次的字符序列。例如,在匹配连续的空格时,\s{2,} 可以匹配至少两个连续的空格。 |
{n,m} |
重复 n 到 m 次 | 示例:a{2,4} 匹配字符串中出现 2 到 4 次的字符 a ,如匹配 aa 、aaa 、aaaa 。常用于匹配字符出现次数在一定范围内的场景。例如,在匹配密码时,[a-zA-Z0-9]{6,12} 可以匹配长度为 6 到 12 位的密码。 |
这些语法在正则表达式中非常常用,通过合理使用它们,可以实现灵活的字符串匹配和提取功能。
有了这些限定符之后,我们就可以对之前的正则表达式进行改造了,比如:
- 匹配 8 位数字的 QQ 号码:
^\d{8}$
- 匹配 1 开头 11 位数字的手机号码:
^1\d{10}$
- 匹配银行卡号是 14~18 位的数字:
^\d{14,18}$
- 匹配以
a
开头的,0 个或多个b
结尾的字符串:^ab*$
看上去更简洁了!
4. 分组
从上面的例子(4)中看到,*
限定符是作用在与他左边最近的一个字符。
如果我想要
ab
同时被*
限定那怎么办呢?
正则表达式中用小括号 ()
来做分组,也就是括号中的内容作为一个整体。因此当我们要匹配多个 ab
时,我们可以这样:如匹配字符串中包含 0 到多个 ab
开头:^(ab)*
5. 转义
我们看到正则表达式用小括号来做分组。
如果要匹配的字符串中本身就包含小括号,那是不是冲突?应该怎么办?
针对这种情况,正则提供了转义的方式,也就是要把这些元字符、限定符或者关键字转义成普通的字符,做法很简单,就是在要转义的字符前面加个斜杠,也就是 \
即可。如:要匹配以 (ab)
开头:^\((ab)\)*
6. 条件或
回到我们刚才的手机号匹配,我们都知道:国内号码都来自三大网,它们都有属于自己的号段,比如联通有 130/131/132/155/156/185/186/145/176 等号段。
假如让我们匹配一个联通的号码,那按照我们目前所学到的正则,应该无从下手的,因为这里包含了一些并列的条件,也就是“或”,那么在正则中是如何表示“或”的呢?
正则用符号 |
来表示或,也叫做分支条件,当满足正则里的分支条件的任何一种条件时,都会当成是匹配成功。那么我们就可以用“或”条件来处理这个问题:^(130|131|132|155|156|185|186|145|176)\d{8}$
7. 区间
正则提供一个元字符中括号 []
来表示区间条件。限定 0 到 9 可以写成 [0-9]
,限定 A-Z 写成 [A-Z]
,限定某些数字 [165]
。
那上面的正则我们还改成这样:^((13[0-2])|(15[56])|(18[5-6])|145|176)\d{8}$
8. 反义
我们会有有一些不是数组,不是字符的需求,所以就有了反义词。
代码/语法 | 说明 |
---|---|
\W |
匹配任意不是字母,数字,下划线,汉字的字符 |
\S |
匹配任意不是空白符的字符 |
\D |
匹配任意非数字的字符 |
\B |
匹配不是单词开头或结束的位置 |
[^x] |
匹配除了 x 以外的任意字符 |
9. 常用表达式
9.1 数字表达式
- 数字:
^[0-9]*$
- n 位的数字:
^\d{n}$
- 至少 n 位的数字:
^\d{n,}$
- m-n 位的数字:
^\d{m,n}$
- 零和非零开头的数字:
^(0|[1-9][0-9]*)$
- 非零开头的最多带两位小数的数字:
^([1-9][0-9]*)+(\.[0-9]{1,2})?$
- 带 1-2 位小数的正数或负数:
^(\-)?\d+(\.\d{1,2})$
- 正数、负数、和小数:
^(\-|\+)?\d+(\.\d+)?$
- 有两位小数的正实数:
^[0-9]+(\.[0-9]{2})?$
- 有 1~3 位小数的正实数:
^[0-9]+(\.[0-9]{1,3})?$
- 非零的正整数:
^[1-9]\d*$
或^([1-9][0-9]*){1,3}$
或^\+?[1-9][0-9]*$
- 非零的负整数:
^\-[1-9][0-9]*$
或^-[1-9]\d*$
- 非负整数:
^\d+$
或^[1-9]\d*|0$
- 非正整数:
^-[1-9]\d*|0$
或^((-\d+)|(0+))$
- 非负浮点数:
^\d+(\.\d+)?$
或^[1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0$
- 非正浮点数:
^((-\d+(\.\d+)?)|(0+(\.0+)?))$
或^(([1-9]\d*\.\d*|0\.\d*[1-9]\d*))|0?\.0+|0$
- 正浮点数:
^[1-9]\d*\.\d*|0\.\d*[1-9]\d*$
或^(([09]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[09]+)|([0-9]*[1-9][0-9]*))$
- 负浮点数:
^-([1-9]\d*\.\d*|0\.\d*[1-9]\d*)$
或((([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*)))$
- 浮点数:
^(-?\d+)(\.\d+)?$
或^-?([19]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0)$
9.2 字符表达式
- 汉字:
^[一-龥]{0,}$
- 英文和数字:
^[A-Za-z0-9]+$
或^[A-Za-z0-9]{4,40}$
- 长度为 3-20 的所有字符:
^.{3,20}$
- 由 26 个英文字母组成的字符串:
^[A-Za-z]+$
- 由 26 个大写英文字母组成的字符串:
^[A-Z]+$
- 由 26 个小写英文字母组成的字符串:
^[a-z]+$
- 由数字和 26 个英文字母组成的字符串:
^[A-Za-z09]+$
- 由数字、26 个英文字母或者下划线组成的字符串:
^\w+$
或^\w{3,20}$
- 中文、英文、数字包括下划线:
^[一龥A-Za-z0-9_]+$
- 中文、英文、数字但不包括下划线等符号:
^[一-龥A-Za-z0-9]+$
或^[一龥A-Za-z0-9]{2,20}$
- 可以输入含有
^%&',;=?$"
等字符:[^%&',;=? $\x22]+
- 禁止输入含有
~
的字符:[^~\x22]+
9.3 常用表达式
- Email 地址:
^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+ ([-.]\w+)*$
- 域名:
[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(\.[a-zAZ0-9][-a-zA-Z0-9]{0,62})+\.?
- Internet URL:
[a-zA-z]+://[^\s]*
或^[http://([\w]+\.)+[\w-]+(/[\w-./?%&=]*)?$
](http://([\w]+\.)+[\w-]+(/[\w-./?%&=]*)?$`) - 手机号码:
^(13[09]|14[5|7]|15[0|1|2|3|4|5|6|7|8|9]|18[0|1|2|3|5|6|7| 8|9])\d{8}$
- 电话号码("XXX-XXXXXXX"、"XXXXXXXXXXXX"、"XXX-XXXXXXX"、"XXXXXXXXXXX"、"XXXXXXX" 和 "XXXXXXXX"):
^(\ (\d{3,4}-)|\d{3.4}-)?\d{7,8}$
- 国内电话号码(0511-4405222、02187888822):
\d{3}-\d{8}|\d{4}-\d{7}
- 电话号码正则表达式(支持手机号码,3-4 位区号,7-8 位直播号码,1-4 位分机号):
((\d{11})|^((\d{7,8})|(\d{4}|\d{3})-(\d{7,8})| (\d{4}|\d{3})-(\d{7,8})-(\d{4}|\d{3}|\d{2}|\d{1})| (\d{7,8})-(\d{4}|\d{3}|\d{2}|\d{1}))$)
- 身份证号(15 位、18 位数字),最后一位是校验位,可能为数字或字符 X:
(^\d{15}$)|(^\d{18}$)|(^\d{17} (\d|X|x)$)
- 帐号是否合法(字母开头,允许 5-16 字节,允许字母数字下划线):
^[a-zA-Z][a-zA-Z0-9_]{4,15}$
- 密码(以字母开头,长度在 6~18 之间,只能包含字母、数字和下划线):
^[a-zA-Z]\w{5,17}$
- 强密码(必须包含大小写字母和数字的组合,不能使用特殊字符,长度在 8-10 之间):
^(?=.*\d)(?=.*[az])(?=.*[A-Z])[a-zA-Z0-9]{8,10}$
- 强密码(必须包含大小写字母和数字的组合,可以使用特殊字符,长度在 8-10 之间):
^(?=.*\d)(?=.*[az])(?=.*[A-Z]).{8,10}$
- 日期格式:
^\d{4}-\d{1,2}-\d{1,2}
- 一年的 12 个月(01~09 和 1~12):
^(0?[1-9]|1[0-2])$
- 一个月的 31 天(01~09 和 1~31):
^((0?[1-9])|((1|2)[0-9])|30|31)$
原创文章,作者:曾确令,如若转载,请注明出处:https://www.zengqueling.com/zzbdsrmjc/