正则表达式语法有点复杂,而且不同的工具或编程语言所支持的语法也不完全相同。下面介绍一些常用的正则表达式语法规则,并顺带提醒几处常见差异。
基本单位
基本单位主要包含:普通字符、转义字符(如 \n、\d)、点号 .(通常匹配除换行外的任意单个字符)、字符类(如 [abc]、[^abc],其中后者表示对字符类取反),以及分组(如 (...))。
基本操作
基本操作的对象是这些基本单位,主要包含两个基本操作:连接和重复。
连接
将两个或多个字符或子模式直接拼接在一起进行匹配。每个子模式会按顺序依次匹配字符串中的相应部分。
- 简单字符连接
正则表达式:abc
匹配:字符串中的 abc 片段。
例子:在“查找”场景下,abc 可以匹配 abc 和 123abc456 中的 abc 片段;如果要求整个字符串完全匹配,应写成 ^abc$,这时 ab 和 abcd 都不匹配。
- 带有转义字符的连接
正则表达式:\.txt$
解释:. 通常表示匹配任意单个字符,而 \. 表示将点号转义为普通字符,即匹配字面量 .;末尾的 $ 表示必须以 .txt 结尾。
匹配:file.txt、document.txt 等以 .txt 结尾的字符串;file.pdf 不匹配。
- 字符类连接
正则表达式:[A-Z][0-9]
解释:第一个字符是大写字母,第二个字符是数字。
匹配:像 “A1”, “Z9” 这样的字符串。
- 带有量词的连接
正则表达式:a{2}b{3}
解释:表示有两个 “a” 和三个 “b” 连在一起。
匹配:”aabbb”。
- 复杂子模式连接
正则表达式:(\d{3})-(\d{2})-(\d{4})
解释:匹配形如 “123-45-6789” 的字符串,其中 \d 表示数字,{3}、{2} 和 {4} 分别指定数字的个数。
匹配:像 “123-45-6789” 这样的字符串。
重复
用于匹配一个模式的多次重复,通常使用量词来控制重复的次数。以下是常用的重复操作符和它们的含义:
常用量词:
*(星号):匹配前面的模式 >= 0 次。例子:
a*可以匹配 “a” 重复 0 次或多次,因此会匹配 “”(空字符串)、”a”、”aa”、”aaa” 等。[abc]*可以匹配零个或多个由字母a、b、c组成的字符序列,如 “”、”a”、”b”、”bacabc” 等。.*可以匹配任意长度的字符序列;不过在很多正则引擎中,.默认不匹配换行符。+(加号):匹配前面的模式 1 次或多次。例子:
a+匹配至少一个 “a”,所以会匹配 “a”,”aa”,”aaa” 等,但不会匹配空字符串。[abc]+可以匹配由字符a、b、c组成的非空字符串,如 “a”、”ab”、”cba”。?(问号):匹配前面的模式 0 次或 1 次。例子:
a?匹配一个 “a” 或没有 “a”,所以会匹配 “” 或 “a”。[abc]?可以匹配零次或一次出现的字母a、b或c,如 “”、”a”、”b”、”c”,但不能匹配 “ab”。{n}:匹配前面的模式恰好 n 次。例子:
a{3}只会匹配 “aaa”,因为它要求 “a” 恰好出现 3 次。{n,}:匹配前面的模式至少 n 次。例子:
a{2,}匹配 “a” 至少出现 2 次的情况,因此会匹配 “aa”、”aaa”、”aaaa” 等。{n,m}:匹配前面的模式至少 n 次,最多 m 次。例子:
a{2,4}会匹配 “a” 出现 2 次到 4 次的情况,因此会匹配 “aa”、”aaa”、”aaaa”。
指定基本单位出现的位置
^:开头位置;在多行模式下常表示行首,比如^1表示以1开头。$:结尾位置;在多行模式下常表示行尾,比如xyz$表示以xyz结尾。\<:词首,比如\<f表示词首必须以f开头。这个写法只在部分正则引擎中有效。\>:词尾,比如xyz\>表示词尾必须以xyz结尾。这个写法只在部分正则引擎中有效。
如果你使用的是更常见的 PCRE、JavaScript、Python 等正则风格,单词边界通常更常写成 \b。
实战演习小例子:
中国电话号码正则表达式
要求:1. 第一位必须是 1;2. 第二位是 3-9 之间的数字;3. 一共 11 位数字。
1 | ^1[3-9]\d{9}$ |
解释:
^:表示字符串的开始,确保从开头匹配。1:中国手机号码以 1 开头。[3-9]:第二位数字是 3 到 9,因为中国的手机号码段通常是 13x, 14x, 15x, 16x, 17x, 18x, 19x 等等。\d{9}:表示接下来有 9 位数字,\d 表示数字,{9} 表示恰好 9 位。$:表示字符串的结尾,确保整个字符串是完整的 11 位号码。
身份证号码正则表达式
要求:1. 一共 18 位;2. 前 6 位是地区码;3. 中间 8 位是出生年月日;4. 最后 3 位是顺序码;5. 最后一位可以是数字,也可以是字母 X。
1 | ^\d{6}(18|19|20)\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])\d{3}(\d|X|x)$ |
解释:
^:表示字符串的开始,确保从开头匹配。\d{6}:前 6 位是地区码,由 6 位数字组成。(18|19|20):接下来的 2 位是年份的前两位,匹配 18、19 或 20(即 1800 年代、1900 年代或 2000 年代)。\d{2}:匹配年份的后两位数字,组成 4 位年份(如 1980、2002 等)。(0[1-9]|1[0-2]):匹配月份,01 到 09 表示 1 月到 9 月,10 到 12 表示 10 月到 12 月。(0[1-9]|[12]\d|3[01]):匹配日期,01 到 09 表示 1 日到 9 日,10 到 29 表示 10 日到 29 日,30 和 31 表示 30 日和 31 日。\d{3}:匹配顺序码,由 3 位数字组成。(\d|X|x):最后一位是校验码,可能是数字或字母X。有些场景只接受大写X,这里同时放行了大小写两种写法。$:表示字符串的结尾,确保整个字符串是完整的 18 位号码。
注意:这个正则只能校验“格式是否像身份证号”,不能严格判断地区码是否真实存在,也不能完全判断日期是否合法,例如闰年和某些月份的天数问题仍需额外逻辑处理。
匹配字符串
要求:1. 匹配单词;2. 开头以 f;3. 结尾为 t。
1 | \<f[a-z]*t\> # 只匹配由小写字母组成的单词 |
解释:
\<:表示单词的开始边界(这在一些正则表达式引擎中有效,如 GNU grep、sed 等)。表示匹配一个单词的起始位置,确保匹配的是独立的单词,而不是其他词中的一部分。f:字母f,匹配单词的第一个字母。[^ \t]*:[^ \t]:字符类取反,表示不能包含空格()或制表符(\t)。*:量词,表示前面的模式可以重复 0 次或多次,即允许后续任意多个非空格或非制表符的字符。
t:字母t,匹配单词的最后一个字母。\>:表示单词的结束边界,确保匹配的结束处是一个完整的单词。
- 本文作者: 迪丽惹Bug
- 本文链接: https://lyroom.github.io/2024/10/11/正则表达式学习/
- 版权声明: 本博客所有文章除特别声明外,均采用 MIT 许可协议。转载请注明出处!