简介
正则表达式(Regular Expression,简称 regex 或 regexp)是一种用来匹配和处理文本的模式表示法。它提供了一套强大的搜索、替换和处理文本的工具,用于描述特定的字符序列。
用途:
- 文本搜索
- 文本替换
- 数据验证:如验证电子邮件地址、电话号码、邮政编码等格式是否正确。
- 数据提取:从日志文件、网页、文档等复杂文本中提取需要的信息。
视频教程
入门
src="https://player.bilibili.com/player.html?isOutside=true\&aid=625512607\&bvid=BV19t4y1y7qP\&cid=187302262\&p=1" data-src="//player.bilibili.com/player.html?isOutside=true&aid=625512607&bvid=BV19t4y1y7qP&cid=187302262&p=1" scrolling="no" border="0" frameborder="no" framespacing="0" allowfullscreen="true" style="width: 710px; height: 392px;"/>
进阶
src="https://player.bilibili.com/player.html?isOutside=true\&aid=625512607\&bvid=BV19t4y1y7qP\&cid=187492466\&p=2" data-src="//player.bilibili.com/player.html?isOutside=true&aid=625512607&bvid=BV19t4y1y7qP&cid=187492466&p=2" scrolling="no" border="0" frameborder="no" framespacing="0" allowfullscreen="true" style="width: 706px; height: 397px;"/>
复习
src="https://player.bilibili.com/player.html?isOutside=true\&aid=670394789\&bvid=BV1da4y1p7iZ\&cid=260601529\&p=1" data-src="//player.bilibili.com/player.html?isOutside=true&aid=670394789&bvid=BV1da4y1p7iZ&cid=260601529&p=1" scrolling="no" border="0" frameborder="no" framespacing="0" allowfullscreen="true" style="width: 708px; height: 419px;"/>
基础语法
正则表达式由普通字符(字母、数字)和元字符(例如.
、*
等)组成,这些字符和元字符形成了匹配规则。
普通字符
直接匹配字符串,例如文本 /etc/apt/sources.list 内容为:
bash
# newer versions of the distribution.
deb http://cn.archive.ubuntu.com/ubuntu/ jammy main restricted
# deb-src http://cn.archive.ubuntu.com/ubuntu/ jammy main restricted
## Major bug fix updates produced after the final release of the
## distribution.
deb http://cn.archive.ubuntu.com/ubuntu/ jammy-updates main restricted
# deb-src http://cn.archive.ubuntu.com/ubuntu/ jammy-updates main restricted
此处忽略几十行
过滤掉注释和空行:
bash
cat /etc/apt/sources.list | grep 'deb http'
bash
deb http://cn.archive.ubuntu.com/ubuntu/ jammy main restricted
deb http://cn.archive.ubuntu.com/ubuntu/ jammy-updates main restricted
deb http://cn.archive.ubuntu.com/ubuntu/ jammy universe
deb http://cn.archive.ubuntu.com/ubuntu/ jammy-updates universe
deb http://cn.archive.ubuntu.com/ubuntu/ jammy multiverse
deb http://cn.archive.ubuntu.com/ubuntu/ jammy-updates multiverse
deb http://cn.archive.ubuntu.com/ubuntu/ jammy-backports main restricted universe multiverse
deb http://security.ubuntu.com/ubuntu/ jammy-security main restricted
deb http://security.ubuntu.com/ubuntu/ jammy-security universe
deb http://security.ubuntu.com/ubuntu/ jammy-security multiverse
元字符
元字符 | 含义 | 示例 | ||||
---|---|---|---|---|---|---|
. |
匹配除换行符以外的任意单个字符 | a.c 可以匹配 "abc"、"adc"、"a1c" 等 |
||||
^ |
匹配字符串的开头 | ^abc 匹配以 "abc" 开头的字符串 |
||||
< / c o d e > < / t d > < t d > 匹配字符串的结尾 < / t d > < t d > < c o d e > a b c | 匹配字符串的结尾 | abc | 匹配字符串的结尾 | abc 匹配以 "abc" 结尾的字符串 |
||
* |
匹配前面的元素零次或多次 | ab*c 匹配 "ac"、"abc"、"abbc" 等 |
||||
+ |
匹配前面的元素一次或多次 | ab+c 匹配 "abc"、"abbc",但不匹配 "ac" |
||||
? |
匹配前面的元素零次或一次 | ab?c 匹配 "ac"、"abc" |
||||
[] |
定义字符类,匹配方括号中任意一个字符 | [aeiou] 匹配任何一个元音字母 [a-z] 匹配所有小写字母 |
||||
` | ` | 表示"或"关系,匹配两者之一 | ||||
() |
用于分组,影响量词作用范围 | (ab)+ 匹配 "ab"、"abab"、"ababab" 等 |
||||
\ |
用于转义下一个字符,使其失去特殊含义。匹配它们的字面意义。 | \. 可以匹配句号. 本身(字面) \\ 可以匹配本身\ 本身(字面) |
字符类
字符 | 作用 | 写法示例 |
---|---|---|
[...] | 匹配括号内的任意一个字符 | [abc] 匹配 "a"、"b" 或 "c" 中的任意一个字符 |
[^...] | 匹配不在括号内的任意字符 | [^abc] 匹配除了 "a"、"b"、"c" 以外的任意字符 |
过滤掉注释和空行:
bash
cat /etc/apt/sources.list | grep -P '^[^#]'
分组语法
符号:使用括号 ()
将多个字符或子表达式视为一个整体。
用途:捕获子串、重复匹配、替换部分内容等。
1. 捕获分组
捕获分组将匹配到的内容存储起来,便于后续操作,比如提取子串或替换匹配部分。
语法 :(pattern)
例如:
regex
(ab)c
- 这里
(ab)
是一个捕获分组,匹配到 "ab",后面紧跟一个 "c"。匹配结果会将 "ab" 存储为一个组。
示例:提取电话号码中的区号
regex
(\d{3})-(\d{3})-(\d{4})
-
输入字符串:
123-456-7890
-
捕获分组1:
123
(区号) -
捕获分组2:
456
-
捕获分组3:
7890
通过捕获分组,可以很容易地提取到区号或其他部分。
2. 非捕获分组
有时我们只想对表达式进行分组,但不需要捕获其中的内容。这时可以使用非捕获分组。
语法 :(?:pattern)
非捕获分组不会保存匹配的内容,只用于逻辑上的分组或应用操作。
例如:
regex
(?:ab)+
- 匹配 "ab" 的一次或多次重复,但不会将每次匹配的 "ab" 作为捕获分组存储。
3. 命名捕获分组
有时为了更好地管理分组,尤其是在复杂的正则表达式中,可以为捕获分组指定名称,以便更清晰地引用。
语法 :(?<name>pattern)
例如:
regex
(?<area_code>\d{3})-(?<prefix>\d{3})-(?<line_number>\d{4})
- 这段正则表达式捕获电话中的不同部分,并为每个部分指定了名字:
area_code
、prefix
和line_number
。 - 这样,匹配到的电话号码部分就可以通过名称来引用,而不是通过数字索引。
4. 引用分组
捕获分组在匹配完成后,可以通过反向引用的方式再次使用已经捕获的内容。反向引用通过 \数字
来表示,其中 数字
是捕获组的编号。
例如:
regex
(\w)\1
- 这里的
(\w)
捕获了一个单词字符,\1
则引用了这个捕获的字符。因此,它可以匹配两个相同的字符连续出现的情况,比如 "aa" 或 "bb"。
示例:匹配重复的单词
regex
\b(\w+)\b\s+\1\b
- 匹配两个连续相同的单词,如
hello hello
。 - 捕获分组
(\w+)
保存了第一个单词,\1
则引用这个单词,以匹配后续的重复单词。
5. 分组的嵌套
分组可以嵌套使用,一个分组内部可以包含其他分组,匹配到的内容会依次按左括号出现的顺序编号。
例如:
regex
((\d{3})-(\d{4}))
- 捕获分组1:
(\d{3})-(\d{4})
(整个字符串) - 捕获分组2:
\d{3}
(前三位数字) - 捕获分组3:
\d{4}
(后四位数字)
示例应用:
1. 提取日期
假设我们要提取日期格式为 YYYY-MM-DD
的字符串中的年份、月份和日期:
regex
(\d{4})-(\d{2})-(\d{2})
-
捕获分组1:年份(4位数字)。
-
捕获分组2:月份(2位数字)。
-
捕获分组3:日期(2位数字)。
输入字符串
2024-09-22
,捕获结果为: -
分组1:
2024
-
分组2:
09
-
分组3:
22
2. 替换文本中的部分内容
假设有一个文本:"My phone number is 123-456-7890"
,我们想用 ***
替换中间三位数字:
python
import re
text = "My phone number is 123-456-7890"
result = re.sub(r'(\d{3})-(\d{3})-(\d{4})', r'\1-***-\3', text)
print(result)
# 输出: My phone number is 123-***-7890
总结
- 捕获分组用于匹配和存储子串。
- 非捕获分组用于逻辑上的分组,而不捕获内容。
- 命名捕获分组通过命名使表达式更加易读。
- 反向引用允许在正则表达式中重新使用已经捕获的内容。
复用语法
复用规则可以让表达式更简洁。
(1)快捷元符号(基础元符号的简便写法)
元字符 | 作用 |
---|---|
\d | 匹配任意数字,相当于 [0-9] |
\D | 匹配任意非数字字符,相当于 [^0-9] |
\w | 匹配任意字母、数字或下划线字符,相当于 [a-zA-Z0-9_] |
\W | 匹配任意非字母、数字或下划线字符,相当于 [^a-zA-Z0-9_] |
\s | 匹配任意空白字符,包括空格、制表符、换行符等 |
\S | 匹配任意非空白字符 |
\b | 匹配单词边界 |
\B | 匹配非单词边界 |
(2)量词(量词不是元符号,用来指定前面元素的重复次数。)
字符 | 作用 | 写法示例 |
---|---|---|
{n} | 匹配前面的元素恰好 n 次 | a{2} 匹配 "aa" |
{n,} | 匹配前面的元素至少 n 次 | a{2,} 匹配 "aa"、"aaa" 等 |
{n,m} | 匹配前面的元素至少 n 次,但不超过 m 次 | a{2,4} 匹配 "aa"、"aaa" 或 "aaaa" |
断言语法
断言本身不匹配字符,它只是定义了一个条件,要求在某个位置满足特定条件才能继续匹配。
- 正向先行断言(后面满足条件) :用
(?=...)
表示,表示在当前位置之后的字符串需要满足括号中的条件才能匹配。
例如,正则表达式foo(?=bar)
会匹配后面紧跟着bar
的foo
。 - 负向先行断言(后面不满足条件) :用
(?!...)
表示,表示在当前位置之后的字符串不能满足括号中的条件才能匹配。
例如,正则表达式foo(?!bar)
会匹配后面不是bar
的foo
。 - 正向后顾断言(前面满足条件) :用
(?<=...)
表示,表示在当前位置之前的字符串需要满足括号中的条件才能匹配。
例如,正则表达式(?<=foo)bar
会匹配前面紧跟着foo
的bar
。 - 负向后顾断言(前面不满足条件) :用
(?<!...)
表示,表示在当前位置之前的字符串不能满足括号中的条件才能匹配。
例如,正则表达式(?<!foo)bar
会匹配前面不是foo
的bar
。
在线练习
-
正则表达式在线测试工具:regex101.com
-
正则在线测试工具:egexr-cn.com
-
正则练习:codejiaonang.com
sandbox="allow-forms allow-presentation allow-same-origin allow-scripts allow-modals" src="https://codejiaonang.com/" data-src="" border="0" frameborder="no" framespacing="0" allowfullscreen="true" style="width: 1169px; height: 655px;"/>