正则表达式
正则表达式
一、概述
正则表达式(Regular Expression)是一种用于匹配文本的模式,广泛应用于文本搜索、替换、数据验证等领域。它通过定义规则来描述字符串的格式和内容,可以匹配复杂的文本结构。
二、匹配单个字符
在正则表达式中,匹配单个字符是构建复杂模式的基础。主要包括普通字符和特殊字符(如点号
.
)。以下是对这两种匹配单个字符方式的详细说明:
1. 普通字符
定义:普通字符是指除正则表达式元字符(如
.
, *
, +
, ?
,
^
, $
, []
, ()
,
{}
, |
, \
等)之外的所有字符。它们在正则表达式中代表自身,直接用于匹配文本中的相应字符。
用法: - 直接匹配:普通字符直接在正则表达式中出现,表示要匹配该字符本身。
示例: - 匹配单个字符: -
正则表达式:a
- 匹配字符串:"apple" 中的第一个 "a"
- 匹配多个普通字符:
- 正则表达式:
cat
- 匹配字符串:"The cat sat on the mat." 中的 "cat"
- 正则表达式:
- 匹配带有特殊意义的字符:
- 如果需要匹配元字符本身,如
.
、*
,必须使用转义字符\
。 - 例如,匹配句点
.
:- 正则表达式:
\.
- 匹配字符串:"End of sentence." 中的句点。
- 正则表达式:
- 如果需要匹配元字符本身,如
注意事项: -
区分大小写:默认情况下,正则表达式是区分大小写的。例如,a
不匹配 A
。可以使用标志(如 i
)来忽略大小写。 -
转义字符:当普通字符与元字符冲突时,需要使用反斜杠
\
进行转义。例如,要匹配字符 *
,应使用
\*
。
示例代码:
1 | import re |
2. 点号(.
)
定义:点号 .
是一个特殊的正则表达式元字符,用于匹配除换行符(\n
)之外的任意单个字符。
用法:
- 通配符:在正则表达式中使用
.
可以匹配任何字符(除换行符),常用于模糊匹配。
示例: - 基本用法: -
正则表达式:a.b
- 匹配字符串:"aab", "acb", "a3b" 等,匹配
"a" 后跟任意一个字符,再跟 "b"
- 多重通配:
- 正则表达式:
...
- 匹配任何三个连续的字符,如 "abc", "123", "a b"
- 正则表达式:
- 与重复符结合:
- 正则表达式:
a.*b
- 匹配以 "a" 开头,以 "b" 结尾,中间可以有任意数量的任意字符,如 "ab", "a123b", "a!@#b"
- 正则表达式:
高级用法:
匹配换行符:
- 默认情况下,
.
不匹配换行符。如果需要匹配包括换行符在内的任意字符,可以使用 单行模式(re.DOTALL
或s
标志)。
示例:
1
2
3
4
5
6
7
8
9
10
11
12import re
# 默认情况下,'.' 不匹配换行符
pattern = r'a.b'
text = 'a\nb'
match = re.search(pattern, text)
print(match) # 输出: None
# 使用 re.DOTALL 使 '.' 匹配换行符
match = re.search(pattern, text, re.DOTALL)
if match:
print(match.group()) # 输出: a\nb- 默认情况下,
非贪婪匹配:
- 与重复符(如
*
、+
)结合使用时,.
可以进行非贪婪匹配,尽可能少地匹配字符。
示例:
1
2
3
4
5
6
7
8
9
10
11
12
13import re
text = '<div>Content</div><div>More Content</div>'
# 贪婪匹配
pattern = r'<div>.*</div>'
match = re.search(pattern, text)
print(match.group()) # 输出: <div>Content</div><div>More Content</div>
# 非贪婪匹配
pattern = r'<div>.*?</div>'
match = re.search(pattern, text)
print(match.group()) # 输出: <div>Content</div>- 与重复符(如
常见误区:
- 误认为
.
匹配换行符:- 很多人初学时误以为
.
可以匹配所有字符,包括换行符。实际上,需要使用单行模式或特定的标志来实现这一点。
- 很多人初学时误以为
- 过度依赖
.
进行匹配:- 虽然
.
是强大的通配符,但在某些情况下,过度使用可能导致匹配过于宽泛,难以控制。应根据具体需求合理使用。
- 虽然
最佳实践:
明确需求:在使用
.
时,确保明确知道它匹配的范围,必要时使用限定符或其他元字符进行精确控制。结合其他元字符:
.
通常与其他元字符(如*
,+
,?
,[]
,()
等)结合使用,以构建更复杂和精确的匹配模式。使用模式标志:根据需要调整正则表达式的行为,如使用
re.DOTALL
让.
匹配换行符,或使用re.IGNORECASE
进行不区分大小写的匹配。
更多示例:
匹配电子邮件地址中的任意字符:
1
2
3
4
5
6import re
pattern = r'\w+@\w+\.\w+'
text = 'Contact us at support@example.com'
match = re.search(pattern, text)
print(match.group()) # 输出: support@example.com匹配包含特殊字符的文件名:
1
2
3
4
5
6import re
pattern = r'file\.\w+'
text = 'The file.txt is ready.'
match = re.search(pattern, text)
print(match.group()) # 输出: file.txt使用
.
进行复杂匹配:1
2
3
4
5
6
7import re
# 匹配以 "start" 开头,以 "end" 结尾,中间有任意字符
pattern = r'^start.*end$'
text = 'start123end'
match = re.match(pattern, text)
print(match.group()) # 输出: start123end
三、匹配一组字符
- 字符集:
- 定义:字符集使用方括号
[]
包含一组字符,表示可以匹配方括号内的任意一个字符。 - 匹配逻辑:正则表达式引擎会尝试匹配字符串中的单个字符,只要这个字符出现在字符集中即可。
- 示例:
- 正则表达式
[abc]
:- 匹配字符串中的 "a"、"b" 或 "c" 中的任意一个字符。
- 如输入 "apple":
[abc]
会匹配 "a"。 - 如输入 "bake":
[abc]
会匹配 "b"。 - 如输入 "cat":
[abc]
会匹配 "c"。
- 正则表达式
- 组合使用:
[aeiou]
:匹配任意一个元音字母("a"、"e"、"i"、"o"、"u")。[0123456789]
:匹配任意一个数字字符。
- 字符集内的特殊符号:
- 如果字符集内包含元字符如
.
、*
、+
等,它们在字符集中失去特殊意义,仅作为普通字符处理。如:[.*+]
匹配的是 "."、"*"、"+" 三个字符中的任意一个。
- 如果字符集内包含元字符如
- 定义:字符集使用方括号
- 范围:
- 定义:字符集内的字符可以使用连字符
-
来表示一个范围,这样可以简化书写。 - 示例:
[a-z]
:匹配所有小写字母,从 "a" 到 "z"。- 如输入 "dog":正则
[a-z]
可以匹配 "d"、"o"、"g" 中的任何一个。 [a-zA-Z]
:匹配所有字母,不区分大小写。
- 如输入 "dog":正则
[0-9]
:匹配所有数字,从 "0" 到 "9"。- 如输入 "2024":正则
[0-9]
可以匹配 "2"、"0"、"2"、"4" 中的任何一个。
- 如输入 "2024":正则
- 多个范围组合:
[a-z0-9]
:匹配小写字母和数字,即小写字母或数字中的任意一个。[A-Fa-f0-9]
:匹配十六进制数字中的任意一个字符,包括 "A-F"、"a-f"、"0-9"。
- 范围的注意事项:
- 范围中的起始字符和结束字符必须按照 ASCII 码的顺序,否则可能产生错误的结果。
- 例如,
[z-a]
是无效的,因为 "z" 的 ASCII 码大于 "a"。
- 定义:字符集内的字符可以使用连字符
- 否定字符集:
- 定义:使用
^
在字符集的开头表示否定字符集,即匹配不在字符集内的任何字符。 - 示例:
[^abc]
:匹配除了 "a"、"b"、"c" 之外的任意字符。- 如输入 "dog":
[^abc]
匹配 "d"、"o"、"g"。
- 如输入 "dog":
[^0-9]
:匹配非数字的字符。- 如输入 "Hello123":
[^0-9]
匹配 "H"、"e"、"l"、"l"、"o"。
- 如输入 "Hello123":
- 定义:使用
- 字符集
[ ]
是匹配任意一个包含的字符。- 范围
[a-z]
可以表示连续字符的范围,简化字符集定义。- 否定字符集
[^ ]
用于匹配不在指定字符集中的字符。
四、使用元字符
元字符是具有特殊意义的字符,能够帮助我们构建更强大的正则表达式。以下是常见的元字符及其功能:
\d
(匹配数字):- 定义:
\d
匹配任意的数字字符。这个元字符等价于字符集[0-9]
,也就是说它可以匹配任意一个从 "0" 到 "9" 的数字。 - 示例:
- 正则表达式
\d
可以匹配字符串中的任何一个数字。 - 如输入 "Price: 45 dollars":
\d
匹配 "4" 和 "5"。\d\d
可以匹配 "45"(连续的两个数字)。
- 正则
\d{3}
匹配三位数字的组合,如 "123" 或 "456"。
- 正则表达式
- 定义:
\w
(匹配字母、数字或下划线):- 定义:
\w
匹配任何字母(大写或小写)、数字或下划线_
。它等价于字符集[A-Za-z0-9_]
。 - 示例:
- 正则表达式
\w
可以匹配任何一个字母、数字或下划线。 - 如输入 "user_name123":
\w
匹配 "u"、"s"、"e"、"r"、"_"、"n"、"a"、"m"、"e"、"1"、"2"、"3"。\w+
可以匹配整个字符串 "user_name123"。
- 正则
\w{5}
可以匹配连续五个字母、数字或下划线的组合,如 "abc12" 或 "user_1"。
- 正则表达式
- 定义:
\s
(匹配空白字符):- 定义:
\s
匹配任何空白字符,包括空格、制表符(Tab)、换行符(\n
)和回车符(\r
)。这对于处理带有空格或其他空白字符的文本时非常有用。 - 示例:
- 正则表达式
\s
可以匹配字符串中的任意一个空白字符。 - 如输入 "Hello World":
\s
匹配两个单词之间的空格。
- 如输入 "Line1":
\s
可以匹配换行符。
- 正则
\s+
可以匹配一个或多个连续的空白字符,适合用来处理多个空格的情况。
- 正则表达式
- 定义:
\D
(匹配非数字):- 定义:
\D
是\d
的反义,匹配任何非数字字符。 - 示例:
- 正则表达式
\D
可以匹配字符串中除了数字以外的任意字符。 - 如输入 "Room 101":
\D
匹配 "R"、"o"、"o"、"m"、" "(空格)。
\D+
匹配连续的非数字字符,如 "Room "。
- 正则表达式
- 定义:
\W
(匹配非字母、数字或下划线):- 定义:
\W
是\w
的反义,匹配任何非字母、非数字或非下划线的字符。 - 示例:
- 正则表达式
\W
可以匹配除了字母、数字和下划线外的任意字符,如标点符号、空格等。 - 如输入 "Hello, World!":
\W
匹配逗号 ","、空格 " " 和感叹号 "!"。
\W+
匹配一个或多个连续的非字母、非数字或非下划线的字符,如匹配 ", World!"。
- 正则表达式
- 定义:
\S
(匹配非空白字符):- 定义:
\S
是\s
的反义,匹配任何非空白字符。 - 示例:
- 正则表达式
\S
可以匹配除了空格、制表符、换行符外的任意字符。 - 如输入 "Hello World":
\S
匹配 "H"、"e"、"l"、"l"、"o"、"W"、"o"、"r"、"l"、"d"。\S+
可以匹配 "Hello" 和 "World" 两个单词。
- 正则表达式
- 定义:
\d
:匹配任何数字字符,等价于[0-9]
。\w
:匹配字母、数字或下划线,等价于[A-Za-z0-9_]
。\s
:匹配任何空白字符,包括空格、制表符、换行符等。\D
、\W
、\S
:分别匹配非数字、非字母/数字/下划线、非空白字符。
五、重复匹配
重复匹配操作符用于指定前一个字符或子表达式出现的次数,从而构建灵活的正则表达式。这些操作符能够匹配多次重复的字符序列。以下是常见的重复匹配操作符及其使用方法:
*
(匹配前一个字符0次或多次):- 定义:
*
表示匹配前一个字符0次或多次,即前一个字符可以不出现,也可以出现多次。 - 示例:
- 正则表达式
a*
:- 匹配空字符串(因为 "a" 可以出现0次)以及任何包含多个 "a" 的字符串。
- 如输入 "":
a*
匹配空字符串。 - 如输入 "aa":
a*
匹配整个字符串 "aa"。 - 如输入 "baaa":
a*
匹配 "aaa" 部分。
.*
(点号.
匹配任意字符,*
匹配0次或多次):- 匹配任意长度的字符串,包括空字符串。
- 如输入 "hello world":
.*
匹配整个字符串。
- 正则表达式
- 定义:
+
(匹配前一个字符1次或多次):- 定义:
+
表示匹配前一个字符1次或多次,即前一个字符至少出现一次。 - 示例:
- 正则表达式
a+
:- 匹配一个或多个连续的 "a" 字符。
- 如输入 "a":
a+
匹配 "a"。 - 如输入 "aaa":
a+
匹配 "aaa"。 - 如输入 "baaa":
a+
匹配 "aaa" 部分。
\d+
(\d
匹配数字,+
匹配1次或多次):- 匹配一个或多个连续的数字。
- 如输入 "123abc456":
\d+
分别匹配 "123" 和 "456"。
- 正则表达式
- 定义:
?
(匹配前一个字符0次或1次):- 定义:
?
表示匹配前一个字符0次或1次,即前一个字符可以出现一次或不出现。 - 示例:
- 正则表达式
a?
:- 匹配0个或1个 "a" 字符。
- 如输入 "":
a?
匹配空字符串。 - 如输入 "a":
a?
匹配 "a"。 - 如输入 "ab":
a?
匹配 "a" 部分。
- 正则表达式
colou?r
:u?
匹配 "u" 0次或1次,能够匹配 "color" 或 "colour"。- 如输入 "color":
colou?r
匹配整个字符串。 - 如输入 "colour":
colou?r
也匹配整个字符串。
- 正则表达式
- 定义:
{n}
(匹配前一个字符恰好n次):- 定义:
{n}
表示匹配前一个字符恰好 n 次,即前一个字符必须精确地出现 n 次。 - 示例:
- 正则表达式
a{3}
:- 匹配连续出现的三个 "a" 字符。
- 如输入 "aaa":
a{3}
匹配整个字符串 "aaa"。 - 如输入 "aaaaa":
a{3}
匹配前三个 "a"。
- 正则表达式
\d{4}
:- 匹配恰好四位的数字。
- 如输入 "2024年":
\d{4}
匹配 "2024"。
- 正则表达式
- 定义:
{n,m}
(匹配前一个字符n到m次):- 定义:
{n,m}
表示匹配前一个字符至少 n 次,至多 m 次。n 和 m 必须是非负整数。 - 示例:
- 正则表达式
a{2,4}
:- 匹配两个到四个连续的 "a" 字符。
- 如输入 "aa":
a{2,4}
匹配 "aa"。 - 如输入 "aaa":
a{2,4}
匹配 "aaa"。 - 如输入 "aaaa":
a{2,4}
匹配 "aaaa"。 - 如输入 "aaaaa":
a{2,4}
匹配前四个 "a"。
- 正则表达式
\d{2,5}
:- 匹配至少两位、至多五位的数字。
- 如输入 "12345":
\d{2,5}
匹配 "12345"。 - 如输入 "123456":
\d{2,5}
匹配前五个数字 "12345"。
- 正则表达式
- 定义:
*
:匹配前一个字符0次或多次,适合匹配任意数量的字符,包括空字符。+
:匹配前一个字符1次或多次,要求至少匹配一个字符。?
:匹配前一个字符0次或1次,通常用于匹配可选字符。{n}
:匹配前一个字符恰好 n 次,适用于精确匹配字符出现的次数。{n,m}
:匹配前一个字符至少 n 次,至多 m 次,提供了灵活的次数范围匹配。
六、位置匹配
位置匹配是一种特殊的匹配方式,它并不匹配具体的字符,而是匹配字符在字符串中的位置。这些位置匹配符号可以用于构建对字符串特定部分的精确匹配条件。以下是常用的几种位置匹配符号及其详细说明:
^
(匹配字符串的起始位置):- 定义:
^
表示匹配字符串的起始位置,通常用于确保字符串以特定字符或子字符串开头。 - 示例:
- 正则表达式
^a
:- 匹配任何以 "a" 开头的字符串。
- 如输入 "apple":
^a
匹配 "a"(因为 "apple" 以 "a" 开头)。 - 如输入 "banana":
^a
不匹配任何内容(因为 "banana" 不是以 "a" 开头)。
- 正则表达式
^Hello
:- 匹配以 "Hello" 开头的字符串。
- 如输入 "Hello, world!":
^Hello
匹配 "Hello"。 - 如输入 "Hi, Hello":
^Hello
不匹配任何内容。
- 正则表达式
- 定义:
$
(匹配字符串的结束位置):- 定义:
$
表示匹配字符串的结束位置,通常用于确保字符串以特定字符或子字符串结尾。 - 示例:
- 正则表达式
a$
:- 匹配任何以 "a" 结尾的字符串。
- 如输入 "banana":
a$
匹配最后的 "a"。 - 如输入 "bananas":
a$
不匹配任何内容(因为 "bananas" 不是以 "a" 结尾)。
- 正则表达式
\d{4}$
:- 匹配以四位数字结尾的字符串。
- 如输入 "Year2024":
\d{4}$
匹配 "2024"。 - 如输入 "ID20245":
\d{4}$
不匹配任何内容(因为 "ID20245" 的最后四位不是单独的数字)。
- 正则表达式
- 定义:
\b
(匹配单词边界):- 定义:
\b
表示单词的边界,即字符的前后位置中,一个是字母数字字符([A-Za-z0-9_]
),另一个不是。它常用于确保匹配的内容是完整的单词,而不是单词的一部分。 - 示例:
- 正则表达式
\bword\b
:- 匹配完整的单词 "word"。
- 如输入 "word":
\bword\b
匹配整个字符串 "word"。 - 如输入 "wordplay":
\bword\b
不匹配(因为 "word" 是 "wordplay" 的一部分)。 - 如输入 "word, play":
\bword\b
匹配 "word"(因为逗号是非字母字符)。
- 正则表达式
\bcat\b
:- 匹配单独的单词 "cat"。
- 如输入 "a black cat":
\bcat\b
匹配 "cat"。 - 如输入 "caterpillar":
\bcat\b
不匹配(因为 "cat" 是 "caterpillar" 的一部分)。
- 正则表达式
- 定义:
\B
(匹配非单词边界):- 定义:
\B
表示非单词边界,即字符的前后位置中,两个都是字母数字字符或两个都不是。它用于确保匹配的内容在单词内部,或在非单词字符的中间。 - 示例:
- 正则表达式
\Bcat\B
:- 匹配单词内部的 "cat"。
- 如输入 "scattering":
\Bcat\B
匹配 "cat" 部分。 - 如输入 "cat":
\Bcat\B
不匹配(因为 "cat" 是完整的单词,没有被其他字符包围)。
- 正则表达式
\Bing
:- 匹配任何在单词内部的 "ing"。
- 如输入 "singing":
\Bing
匹配 "ing" 部分(在单词内部)。 - 如输入 "ring":
\Bing
不匹配(因为 "ing" 是单词结尾部分)。
- 正则表达式
- 定义:
^
:用于匹配字符串的开头位置,确保匹配在字符串的最前面。$
:用于匹配字符串的结尾位置,确保匹配在字符串的最后面。\b
:用于匹配单词的边界,确保匹配的内容是独立的单词或部分。\B
:用于匹配非单词边界,确保匹配的内容在单词内部或非单词字符的中间。
七、使用子表达式
子表达式是正则表达式中一个非常强大的工具,通过将表达式的某一部分括起来,可以对它们进行特殊的处理和操作。这使得正则表达式更加灵活和强大,能够实现复杂的匹配需求。
1. 括号
()
:定义子表达式
- 定义:括号
()
用于将正则表达式的一部分括起来,使其成为一个整体,这部分表达式就称为一个子表达式。 - 作用:
- 分组:将多个字符或表达式作为一个整体对待,以便应用量词、位置匹配或其他操作。
- 捕获:默认情况下,子表达式会捕获匹配的内容,并将其存储在一个临时的缓存区中,可以在后续操作中引用这些匹配的内容。
- 重用:可以在表达式中后续引用之前的捕获组。
- 示例:
- 正则表达式
(abc)+
:- 匹配字符串 "abc" 的一次或多次重复出现。
- 如输入 "abcabc":
(abc)+
匹配整个字符串 "abcabc"。 - 如输入 "abcabcabc":
(abc)+
匹配整个字符串 "abcabcabc"。
- 正则表达式
(ab|cd)+ef
:- 匹配 "ab" 或 "cd" 这两个子串的一次或多次重复出现,并且最后匹配 "ef"。
- 如输入 "abef":匹配 "abef"。
- 如输入 "cdabef":匹配 "cdabef"。
- 如输入 "abcdcdef":匹配 "abcdcdef"。
- 正则表达式
2. 非捕获组
(?:...)
:定义子表达式但不捕获结果
- 定义:非捕获组
(?:...)
也是一种括号语法,用于将表达式的一部分括起来,但与普通括号不同,它不会捕获匹配的内容,不会影响后续捕获组的编号。这种分组在不需要保存匹配结果时非常有用。 - 作用:
- 优化性能:由于不保存匹配结果,因此非捕获组的性能可能会比捕获组略好。
- 避免编号冲突:在复杂的正则表达式中,使用非捕获组可以避免不必要的捕获,保持捕获组的编号一致性。
- 示例:
- 正则表达式
(?:abc)+
:- 匹配字符串 "abc" 的一次或多次重复出现,但不保存匹配结果。
- 如输入 "abcabc":
(?:abc)+
匹配整个字符串 "abcabc",但不会将 "abc" 保存为一个捕获组。
- 正则表达式
(?:ab|cd)+ef
:- 匹配 "ab" 或 "cd" 这两个子串的一次或多次重复出现,并且最后匹配 "ef",但不会捕获 "ab" 或 "cd"。
- 如输入 "abef":匹配 "abef"。
- 如输入 "cdabef":匹配 "cdabef"。
- 正则表达式
子表达式的捕获和引用
- 捕获组的引用:在正则表达式内部,可以通过
\1
,\2
,\3
等方式来引用之前捕获的组。这在进行复杂匹配或替换时非常有用。- 示例:
- 正则表达式
(\d{3})-(\d{2})-(\d{4})
:- 匹配形如 "123-45-6789" 的数字格式,并捕获每一部分。
\1
引用第一个捕获组,即前三位数字 "123"。\2
引用第二个捕获组,即中间两位数字 "45"。\3
引用第三个捕获组,即最后四位数字 "6789"。
- 正则表达式
- 示例:
- 替换中的捕获组:在字符串替换操作中,可以使用捕获组来调整或重新排列匹配的内容。
- 示例:
- 使用正则表达式
(\w+)\s(\w+)
替换"first last"
为"last, first"
:- 捕获第一个单词
(\w+)
,然后捕获第二个单词(\w+)
。 - 替换字符串可以是
"\2, \1"
,将名字和姓氏对调。
- 捕获第一个单词
- 使用正则表达式
- 示例:
()
:定义捕获组,允许分组和捕获匹配的子表达式内容,用于更复杂的匹配和替换。(?:...)
:定义非捕获组,用于分组但不捕获匹配结果,适用于不需要保存匹配内容的场景。- 捕获组的引用:可以通过
\1
,\2
等在表达式内部引用已捕获的内容,或在替换操作中使用捕获组来调整文本。
八、回溯引用
回溯引用(backreference)是一种强大的正则表达式功能,允许在同一个表达式中引用之前捕获的子表达式的匹配内容。这在处理重复的结构或需要保持一致性的匹配时非常有用。
1. 回溯引用的基本概念
- 定义:回溯引用是指在正则表达式中,通过特定的符号
\1
,\2
,\3
等,引用在表达式中之前定义和捕获的子表达式。 - 用途:回溯引用常用于匹配重复出现的内容,或在需要对相同模式进行一致性检查时使用。
2. 使用方法
- 基本语法:
(\text{pattern})\1
表示匹配一个模式并再次匹配相同的模式。(\d)
:表示一个数字,并将其捕获为第一个子表达式。\1
:引用第一个子表达式,要求匹配的字符与之前捕获的内容一致。
- 多个回溯引用:如果有多个子表达式捕获组,可以使用
\2
,\3
等引用它们。(\d)(\w)\2\1
:(\d)
捕获一个数字并存储为\1
。(\w)
捕获一个字母并存储为\2
。\2\1
要求匹配捕获的字母和数字的重复顺序。
3. 回溯引用的实际应用
- 匹配重复字符:
- 示例:正则表达式
(\d)\1
匹配两个连续的相同数字。- 如输入 "00":匹配 "00"。
- 如输入 "112233":可以匹配 "11", "22", "33"。
- 解释:
(\d)
捕获一个数字并存储为第一个子表达式,\1
要求第二个匹配的字符必须与第一个相同。
- 示例:正则表达式
- 匹配重复的字母组合:
- 示例:正则表达式
(\w\w)\1
匹配两个相同的字母组合。- 如输入 "abab":匹配 "abab"。
- 如输入 "xyxy":匹配 "xyxy"。
- 解释:
(\w\w)
捕获两个字母并存储为第一个子表达式,\1
要求匹配的下两个字符与之前捕获的内容一致。
- 示例:正则表达式
- 匹配回文:
- 示例:正则表达式
(\w)(\w)\2\1
匹配一个四个字母的回文结构,如 "abba"。- 如输入 "abba":匹配 "abba"。
- 如输入 "xyyx":匹配 "xyyx"。
- 解释:
(\w)
捕获第一个和第二个字母分别为\1
和\2
,接着\2\1
匹配前两个字母的逆序。
- 示例:正则表达式
4. 特殊场景中的回溯引用
- 替换中的回溯引用:在替换操作中,回溯引用可以用来重新排列或调整匹配内容。
- 示例:使用正则表达式
(\w+)\s(\w+)
替换"first last"
为"last, first"
:- 捕获第一个单词
(\w+)
,并将其存储为\1
。 - 捕获第二个单词
(\w+)
,并将其存储为\2
。 - 替换表达式使用
"\2, \1"
,将名字和姓氏对调。
- 捕获第一个单词
- 示例:使用正则表达式
- 嵌套回溯引用:在复杂表达式中,回溯引用可以嵌套使用,匹配更多层次的内容。
- 示例:正则表达式
((\d)\d)\2
匹配特定的嵌套结构。- 解释:
(\d)
捕获一个数字,(\d)\d
捕获两个数字并作为一个整体引用,\2
匹配第一个数字。
- 解释:
- 示例:正则表达式
- 回溯引用
\1
,\2
等允许在正则表达式中引用之前捕获的内容。- 回溯引用可以用来匹配重复的字符、字母组合,或检查相同模式的一致性。
- 回溯引用在替换操作中也非常有用,可以重新排列或调整匹配的内容。
- 在复杂表达式中,回溯引用可以嵌套使用,实现更加高级的匹配需求。
九、前后查找
前后查找(lookahead 和 lookbehind)是一种高级正则表达式技术,用于在不消耗字符的情况下,检查某个匹配是否满足特定条件。这意味着前后查找本身并不会返回匹配的字符,而是作为一种限制条件来约束其他匹配。
1. 前瞻(Lookahead)
前瞻用于判断一个字符串是否在某个特定的内容之前出现,但这个内容不会包含在最终的匹配结果中。
语法:
(?=...)
解释:
(?=...)
中的...
是一个子表达式,表示如果当前位置满足...
的条件,那么匹配成功,但实际的匹配结果不包括...
。示例:
- 正则表达式:
\d(?=px)
- 作用:匹配紧跟在 "px" 前的数字。
- 匹配字符串:"20px"
- 匹配结果:
20
中的2
,因为它后面跟着 "px"。
- 正则表达式:
应用场景:
- 例如在样式表中,你可能想匹配所有以 "px" 为单位的数字:
- 输入:"margin: 10px; padding: 5px; font-size: 12pt;"
- 匹配正则:
\d+(?=px)
- 结果:
10
和5
,因为它们后面都跟着 "px"。
- 例如在样式表中,你可能想匹配所有以 "px" 为单位的数字:
2. 后顾(Lookbehind)
后顾用于判断一个字符串是否在某个特定的内容之后出现,并且这个内容不会包含在最终的匹配结果中。
语法:
(?<=...)
解释:
(?<=...)
中的...
是一个子表达式,表示如果当前位置之前的字符串满足...
的条件,那么匹配成功,但实际的匹配结果不包括...
。示例:
- 正则表达式:
(?<=\$)\d+
- 作用:匹配紧跟在美元符号
$
后的数字。 - 匹配字符串:"总计: $100"
- 匹配结果:
100
,因为它前面有$
符号。
- 作用:匹配紧跟在美元符号
- 正则表达式:
应用场景:
- 例如在财务数据中,你可能想提取所有以美元表示的数值:
- 输入:"价格:$50, $100, ¥200"
- 匹配正则:
(?<=\$)\d+
- 结果:
50
和100
,因为它们前面都跟着 "$" 符号。
- 例如在财务数据中,你可能想提取所有以美元表示的数值:
3. 负前瞻(Negative Lookahead)
负前瞻用于判断某个字符串是否不在某个特定内容之前出现,且这个内容不会包含在最终的匹配结果中。
语法:
(?!...)
解释:
(?!...)
中的...
是一个子表达式,表示如果当前位置满足...
的条件,则匹配失败,只有不满足...
的情况下,匹配才成功。示例:
- 正则表达式:
\d(?!px)
- 作用:匹配后面不跟 "px" 的数字。
- 匹配字符串:"20pt 30px"
- 匹配结果:
2
和0
,因为它们后面不跟 "px"。
- 正则表达式:
应用场景:
- 例如在文本中,过滤掉特定单位的数值,如排除以 "px" 为单位的数字:
- 输入:"margin: 20px; padding: 10pt; font-size: 15px;"
- 匹配正则:
\d+(?!px)
- 结果:
10
,因为它后面没有 "px"。
- 例如在文本中,过滤掉特定单位的数值,如排除以 "px" 为单位的数字:
4. 负后顾(Negative Lookbehind)
负后顾用于判断某个字符串是否不在某个特定内容之后出现,且这个内容不会包含在最终的匹配结果中。
语法:
(?<!...)
解释:
(?<!...)
中的...
是一个子表达式,表示如果当前位置之前的字符串满足...
的条件,则匹配失败,只有不满足...
的情况下,匹配才成功。示例:
- 正则表达式:
(?<!\$)\d+
- 作用:匹配前面不跟
$
的数字。 - 匹配字符串:"总计: 100 元, $200 美元"
- 匹配结果:
100
,因为它前面没有$
符号。
- 作用:匹配前面不跟
- 正则表达式:
应用场景:
- 例如在文本中,排除特定货币符号的数值:
- 输入:"$100, 200元, $300"
- 匹配正则:
(?<!\$)\d+
- 结果:
200
,因为它前面没有 "$"。
- 例如在文本中,排除特定货币符号的数值:
- 前瞻
(?=...)
和 后顾(?<=...)
用于在不包含条件本身的情况下,对字符串进行条件约束匹配。- 负前瞻
(?!...)
和 负后顾(?<!...)
则用于排除特定条件,使得匹配更加灵活。- 前后查找的强大之处在于它们不消耗字符,因此能够与其他正则表达式结合使用,实现复杂的匹配需求。
十、嵌入条件
正则表达式中的嵌入条件(conditional expressions)允许根据前面的匹配结果选择不同的匹配路径。这使得正则表达式能够处理更复杂的匹配场景,类似于编程中的条件语句。
1. 条件表达式的语法
- 语法:
(?ifthen|else)
if
:表示一个条件子表达式。如果这个子表达式成功匹配,选择then
部分。then
:如果if
部分成功,匹配这个部分。else
:如果if
部分失败,则匹配这个部分(else
是可选的)。
2. 使用条件表达式的示例
- 基本示例:
- 正则表达式:
(?:(\d)\d{2}|(\w)\w{2})
- 解释:这里的正则表达式表示,如果第一个捕获组(
\d
)成功匹配,后面必须是两个数字(\d{2}
)。否则,匹配第二个捕获组(\w
)后面跟两个字母(\w{2}
)。 - 输入:"12ab"
- 匹配结果:
12
匹配第一个部分;ab
匹配第二个部分。
- 匹配结果:
- 解释:这里的正则表达式表示,如果第一个捕获组(
- 正则表达式:
- 复杂示例:
- 正则表达式:
(?:(\d{3})|(\w{2}))(?(1)\d{2}|\w{2})
- 解释:如果第一个捕获组(
(\d{3})
)成功匹配三个数字,那么匹配后面两个数字(\d{2}
)。如果第一个捕获组没有匹配(即匹配两个字母(\w{2})
),则匹配后面两个字母(\w{2}
)。 - 输入:"12345"
- 匹配结果:
123
匹配第一个部分;45
匹配第二个部分。
- 匹配结果:
- 输入:"abxy"
- 匹配结果:
ab
匹配第一个部分;xy
匹配第二个部分。
- 匹配结果:
- 解释:如果第一个捕获组(
- 正则表达式:
3. 应用场景
- 验证特定格式的输入:
- 在需要验证用户输入的格式时,条件表达式可以根据特定条件选择不同的验证规则。例如,验证电话号码或身份证号码的格式,可能根据国家或区域不同而有所变化。
- 处理可变格式的数据:
- 当数据格式可变时,例如日志文件中可能包含不同类型的记录,条件表达式可以根据记录类型选择不同的解析方式。
- 复杂文本处理:
- 在文本处理任务中,特别是那些涉及到多种格式的文本,条件表达式可以根据先前的匹配结果选择适当的后续匹配路径,从而进行更复杂的文本提取。
4. 正则表达式的实际例子
- 例子
1:匹配一个可能是数字或字母,并且其后的部分是固定格式。
- 正则表达式:
(?:(\d)\d{2}|(\w)\w{2})(?(1)\d{2}|\w{2})
- 解释:如果第一个捕获组匹配数字,那么后面必须是两个数字;如果第一个捕获组匹配字母,那么后面必须是两个字母。
- 输入:"12345" 匹配成功,
123
和45
分别对应数字和两个数字。 - 输入:"abxy" 匹配成功,
ab
和xy
分别对应字母和两个字母。
- 正则表达式:
- 例子
2:匹配一个字符串,前缀是数字或字母,并且根据前缀的不同,后缀的规则也不同。
- 正则表达式:
(?:(\d{2,3})|(\w{1,2}))(?(1)\d{3,4}|\w{3,4})
- 解释:如果前面匹配了两个或三个数字,则后面匹配三个或四个数字;如果前面匹配了一个或两个字母,则后面匹配三个或四个字母。
- 输入:"1234567" 匹配成功,
123
和4567
分别对应两个数字和三个数字。 - 输入:"abxyz" 匹配成功,
ab
和xyz
分别对应字母和三个字母。
- 正则表达式:
- 条件表达式
(?ifthen|else)
使得正则表达式能够根据条件选择不同的匹配路径。- 使用场景:验证格式、处理可变格式的数据、复杂文本处理等。
- 实例:可以处理不同格式的数据,根据先前的匹配结果决定后续匹配的内容。