1.小例子
例:在文本中找指定的单词study
\bstudy\b
例:在文本中找指定的一句话,指定开头单词we,和结尾单词you
\bwe\b.*\byou\b
正则表达式测试工具,推荐 match tracer
http://www.regexlab.com/download/?/mtracer/MTracer.zip
2.常用元字符
元字符的作用:匹配字符,匹配位置,匹配数量,匹配模式。
以下是一些常用的正则表达式元字符:
.
: 匹配除换行符以外的任意一个字符。^
: 匹配输入字符串的开始位置。$
: 匹配输入字符串的结束位置。*
: 匹配前面的字符(或子表达式)零次或多次。+
: 匹配前面的字符(或子表达式)一次或多次。?
: 匹配前面的字符(或子表达式)零次或一次。[]
: 字符类,匹配括号内的任意一个字符。|
: 逻辑 OR 操作符,用于匹配两个选择之一。()
: 分组,将其中的内容视为一个整体。\
: 转义字符,用于转义元字符。- \b:匹配单词的开始或结束
- \d:匹配数字
- \w:匹配字母,数字,下划线或汉字
- \s:匹配任意空白字符,包括空格、制表符和换行符等
例:从下面字符串中找到But200和s100的正则表达式
But200 a man is not made for defeat. A man can be destroyed but not defeated. s100
(1)^But\d*
(2)s\d*$
3.字符转义
在正则表达式中,有一些特殊字符具有特殊的含义。如果你想要匹配这些特殊字符本身而非它们的特殊含义,你需要进行字符转义。在正则表达式中,使用反斜杠 \
来进行字符转义。
下面是一些常见的需要进行字符转义的特殊字符:
.
,*
,+
,?
,[
,]
,(
,)
,{
,}
,^
,$
,\
,|
: 这些字符在正则表达式中具有特殊含义,如果你想匹配它们本身,需要在前面加上反斜杠进行转义。\d
,\w
,\s
: 这些是用于匹配数字、单词字符和空白字符的字符类别简写。如果你想匹配它们本身,也需要进行转义,如\\d
,\\w
,\\s
。
例如,如果你想匹配一个句子中的句号 .
,你可以使用正则表达式 \.
进行转义。同样地,如果你想匹配一个数字字符 \d
,你可以使用 \\d
进行转义。
4.匹配重复的限定符
在正则表达式中,重复限定符用于指定前面的字符或子表达式可以重复出现的次数。以下是一些常见的重复限定符:
*
:匹配前面的字符(或子表达式)零次或多次。+
:匹配前面的字符(或子表达式)一次或多次。?
:匹配前面的字符(或子表达式)零次或一次。{n}
:匹配前面的字符(或子表达式)恰好 n 次。{n,}
:匹配前面的字符(或子表达式)至少 n 次。{n,m}
:匹配前面的字符(或子表达式)至少 n 次,但不超过 m 次。
例:匹配worlllld
\bworl{3,5}d\b
例:匹配we1
we\d?
5.字符集
正则表达式字符集用于指定一个字符集合,可以匹配其中的任意一个字符。你可以使用方括号 []
来定义一个字符集,如下所示
[abc] // 匹配 a、b 或 c 中的任意一个字符
[a-z] // 匹配任意小写字母
[A-Z] // 匹配任意大写字母
[0-9] // 匹配任意数字字符
[^\w] // 匹配任意非单词字符(即除了字母、数字和下划线之外的字符)
在字符集中,你可以使用连字符 -
指定一个范围。例如,[a-z]
可以匹配任意一个小写字母,而 [0-9]
可以匹配任意一个数字字符。
如果你想匹配一个特定的字符集合,但是其中包含了正则表达式中的特殊字符,你需要进行字符转义。例如,如果你想匹配字符集合 [+.()]
中的任意一个字符,你可以使用以下正则表达式:
[+\.\(\)]
注意,字符集合中的重复出现的字符只会被匹配一次。例如,[hello]
只会匹配单词 hello
中的每个字符一次。如果你想匹配重复出现的字符,你需要使用重复限定符。
6.分歧条件
在正则表达式中,你可以使用分支条件(alternation)来匹配多个模式中的任意一个。分支条件使用竖线 |
来分隔不同的模式,如下所示:
pattern1|pattern2|pattern3
这个表达式会先尝试匹配 pattern1
,如果匹配成功,则匹配过程停止。如果没有匹配成功,则继续尝试匹配 pattern2
,然后是 pattern3
,依此类推。
例如,假设你想匹配字符串中的 "apple" 或 "orange",你可以使用以下正则表达式:
apple|orange
这样,如果字符串中包含 "apple" 或 "orange" 中的任意一项,正则表达式就会匹配成功。
分支条件还可以与其他正则表达式元字符和限定符结合使用,以构建更复杂的模式。例如:
\d{3}-\d{3}-\d{4}|(\(\d{3}\))?\s?\d{3}-\d{4}
这个正则表达式匹配电话号码,可以接受以下两种格式:xxx-xxx-xxxx 或 (xxx) xxx-xxxx。其中,分支条件 (xxx)
是可选的。
使用分支条件可以灵活地处理多个匹配模式,方便地实现复杂的匹配需求。
7.分组
在正则表达式中,分组是将模式的一部分括在圆括号 ( )
中的一种机制。它可以用于多种目的,包括限定符应用范围、捕获匹配内容和创建子模式等。
下面是几个使用分组的示例:
(1)限定符应用范围:
(abc){3}
这个表达式表示匹配连续出现三次的 "abc"。分组 (abc)
中的限定符 {3}
仅适用于整个分组,而不是单独的字符。
(2)捕获匹配内容:
(\w+)\s(\w+)
这个表达式表示匹配由一个或多个字母数字字符组成的单词,然后是一个空白字符,然后是另一个由一个或多个字母数字字符组成的单词。分组 (\w+)
将捕获匹配到的内容供后续处理使用。
(3)子模式:
(a|b|c)\d
这个表达式表示匹配以 "a"、"b" 或 "c" 开头,后跟一个数字的字符串。分组 (a|b|c)
创建了一个子模式,表示从这三个选项中选择一个进行匹配。
分组还可以与其他正则表达式元字符和限定符结合使用,以构建更复杂的模式。你可以根据具体的匹配需求来选择是否使用分组。
常用的分组形式:
(1)捕获分组:使用圆括号 ( )
表示,可以将匹配到的内容保存到一个变量中,后续可以通过这个变量进行操作。
import re
# 匹配以数字开头和结尾的字符串,并提取其中的数字
s = 'abc123def'
pattern = r'(\d+)'
match = re.search(pattern, s)
print(match.group(1)) # 输出结果为 '123'
(2)非捕获分组:使用 (?: )
表示,与捕获分组类似,但不会将匹配到的内容保存到一个变量中,因此不消耗额外的内存空间。
import re
# 匹配多个连续的单词,其中每个单词之间由空格分隔
s = 'hello world python java'
pattern = r'(?:\w+\s+){3}'
match = re.search(pattern, s)
print(match.group(0)) # 输出结果为 'hello world python '
(3)正向肯定预查:使用 (?= )
表示,表示必须满足括号中的条件,但不会将其作为匹配结果返回。
import re
# 匹配以 hello 开头,后面跟着一个数字或字母,并以 world 结尾的字符串
s = 'hello1 world'
pattern = r'hello(?=\w)world'
match = re.search(pattern, s)
print(match.group(0)) # 输出结果为 'hello1 world'
(4)正向否定预查:使用 (?! )
表示,表示必须不满足括号中的条件,但不会将其作为匹配结果返回。
import re
# 匹配不以 hello 开头的字符串
s = 'world'
pattern = r'^(?!hello).*$'
match = re.search(pattern, s)
print(match.group(0)) # 输出结果为 'world'
8.反义
在正则表达式中,可以使用 ^
符号来表示反义,即匹配不符合指定模式的内容。^
符号在不同的位置会有不同的含义:
-
在字符集
[ ]
中,^
表示取反操作,用于匹配不在字符集中的字符。例如,[^a]
表示匹配除了字母 "a" 之外的任意字符。 -
在正则表达式的开头,
^
表示匹配字符串的开始位置。例如,^abc
表示匹配以 "abc" 开头的字符串。 -
在其他位置,
^
表示反义,用于匹配不符合指定模式的内容。例如,\d
表示匹配数字,而\D
表示匹配非数字的字符。
下面是一些常用的反义符号及其含义:
\d
: 匹配数字字符 (0-9)。\D
匹配非数字字符。\w
: 匹配字母、数字或下划线。\W
匹配非字母、数字或下划线字符。\s
: 匹配空白字符。\S
匹配非空白字符。
通过使用反义符号,你可以更精确地定义你需要匹配的内容,甚至找到与特定模式不匹配的内容。
9.后向引用
当你在正则表达式中使用括号来创建一个分组时,这个分组内匹配到的内容会被保存供以后使用。后向引用就是指向这些保存的内容的引用。
在正则表达式中,后向引用可以通过 \1
, \2
, \3
等来表示。这些符号分别对应着第一个、第二个、第三个括号内匹配到的内容。例如,如果你的正则表达式是 (\w)+\s\1
,它将会匹配重复的单词,其中 \1
将会引用第一个括号内匹配到的内容。
下面是一个更详细的示例:
假设我们要匹配连续出现的相同单词,我们可以使用后向引用来实现。下面是一个简单的例子:
import re
pattern = r'\b(\w+)\s+\1\b'
text = "hello hello world world"
matches = re.findall(pattern, text)
for match in matches:
print("Match found:", match)
在这个例子中,我们使用了 \b(\w+)\s+\1\b
作为正则表达式。这个表达式的含义是:\b
匹配单词边界,(\w+)
匹配一个或多个字母数字字符(即单词),\s+
匹配一个或多个空白字符,然后 \1
引用前面捕获到的内容,最后的 \b
匹配单词边界。这样我们就能够匹配连续出现的相同单词了。
后向引用提供了一种强大的方式来引用先前捕获到的内容,从而使得我们可以更灵活地进行匹配和操作。
10.零宽断言
正则表达式的零宽断言是一种特殊的模式匹配技术,用于指定匹配位置而不消耗实际的字符。
(1)正向先行断言(Positive Lookahead Assertion):匹配某个位置后面紧跟着指定的模式。
import re
pattern = r'\d+(?= dollars)'
text = 'I have 100 dollars in my pocket'
result = re.search(pattern, text)
print(result.group(0)) # 输出: '100'
当我们使用正则表达式进行匹配时,有时候我们希望只匹配某个位置后面紧跟着指定模式的情况,而不包括该模式本身。这就是正向先行断言(Positive Lookahead Assertion)的作用。
让我们逐行解释这段代码的含义:
-
import re
:导入 Python 的正则表达式模块。 -
pattern = r'\d+(?= dollars)'
:定义一个正则表达式模式。该模式使用了零宽度正向先行断言,\d+
表示匹配一串数字,(?= dollars)
表示该数字后面必须紧跟着一个空格和单词"dollars"。 -
text = 'I have 100 dollars in my pocket'
:待匹配的文本。 -
result = re.search(pattern, text)
:使用re.search()
函数在文本中搜索符合模式的字符串。 -
print(result.group(0))
:打印匹配结果的第一个分组。
当使用re.search()函数搜索这个模式时,会成功匹配到"100"这个数字,而不包括"dollars"这个单词。所以最终的输出是'100'。
简单来说,这段代码使用了正向先行断言,通过在匹配模式中添加 (?=...)
来指定一个位置后面必须紧跟着某个模式,从而实现精确匹配。在这个例子中,我们成功匹配到了文本中的 "100",而不是整个 "100 dollars"。
(2)负向先行断言(Negative Lookahead Assertion):匹配某个位置后面不紧跟着指定的模式。
import re
pattern = r'\d+(?! dollars)'
text = 'I have 100 euros in my wallet'
result = re.search(pattern, text)
print(result.group(0)) # 输出: '100'
(3)正向后顾断言(Positive Lookbehind Assertion):匹配某个位置前面紧跟着指定的模式。
import re
pattern = r'(?<=\$)\d+'
text = 'The price is $100'
result = re.search(pattern, text)
print(result.group(0)) # 输出: '100'
当我们使用正则表达式进行匹配时,有时候我们希望只匹配某个位置前面紧跟着指定模式的情况,而不包括该模式本身。这就是正向后顾断言(Positive Lookbehind Assertion)的作用。
下面是代码的详细解析:
-
import re
:导入 Python 的正则表达式模块。 -
pattern = r'(?<=\$)\d+'
:定义一个正则表达式模式。该模式使用了零宽度正向后顾断言,(?<=\$)
表示要匹配的数字前面必须紧跟着一个美元符号"$",\d+
表示匹配一串数字。 -
text = 'The price is $100'
:待匹配的文本。 -
result = re.search(pattern, text)
:使用re.search()
函数在文本中搜索符合模式的字符串。 -
print(result.group(0))
:打印匹配结果的第一个分组。
运行这段代码,输出结果是 '100'
,即匹配到了文本中的 "100",但不包括 "$" 这个符号。
简单来说,这段代码使用了正向后顾断言,通过在匹配模式中添加 (?<=...)
来指定一个位置前面必须紧跟着某个模式,从而实现精确匹配。在这个例子中,我们成功匹配到了文本中的 "100",而不包括 "$" 这个符号。
(4)负向后顾断言(Negative Lookbehind Assertion):匹配某个位置前面不紧跟着指定的模式。
import re
pattern = r'(?<!\$)\d+'
text = 'The price is 100 dollars'
result = re.search(pattern, text)
print(result.group(0)) # 输出: '100'
这段代码使用了正则表达式来匹配文本中不以美元符号"$"作为前导的连续数字。让我来详细解释一下:
-
import re
:导入 Python 的正则表达式模块。 -
pattern = r'(?<!\$)\d+'
:定义一个正则表达式模式。该模式使用了零宽度负向后顾断言(?<!\$)
,表示要匹配的数字前面不能紧跟着美元符号"$",\d+
表示匹配一串数字。 -
text = 'The price is 100 dollars'
:待匹配的文本。 -
result = re.search(pattern, text)
:使用re.search()
函数在文本中搜索符合模式的字符串。 -
print(result.group(0))
:打印匹配结果的第一个分组。
当运行这段代码时,由于模式(?<!\$)\d+
要求匹配的数字前面不能紧跟着美元符号"$",因此它会匹配到文本中的 "100",因为 "100" 前面并没有美元符号。
因此,最终输出结果是 '100'
,即成功匹配到了文本中的 "100"。
总结:通过使用零宽度负向后顾断言(?<!\$)
,这段代码实现了匹配文本中不以美元符号"$"作为前导的数字。
11.注释
在正则表达式中,(?#comment)
是一种注释的方式,可以用于在正则表达式中添加注释而不会影响匹配的行为。这种注释方式不同于使用 re.VERBOSE
标记的多行注释,而是直接在正则表达式中插入单行注释。
当使用正则表达式中的 (?#comment)
时,(?#comment)
是一个注释,不会对匹配产生影响,它可以用来在正则表达式中添加注释以提高可读性。
以下是一个简单的示例,演示如何在正则表达式中使用 (?#comment)
进行注释
import re
# 匹配 email 地址的正则表达式,包括用户名和域名部分
pattern = re.compile(r'''
[\w\.-]+ # 匹配用户名部分
@ # @ 符号
[\w\.-]+ # 匹配域名部分
(?#comment: 这是一个简单的 email 地址匹配正则表达式)
''', re.VERBOSE)
text = "example@example.com"
result = pattern.match(text)
if result:
print(result.group()) # 输出:'example@example.com'
首先我们定义了一个正则表达式模式,使用了 Python 中的 re.compile
方法将其编译为一个正则表达式对象。在这个模式中,我们使用了 re.VERBOSE
标志,它允许我们在正则表达式中添加注释和空白符,以提高可读性。
正则表达式模式如下所示:
'''
[\w\.-]+ # 匹配用户名部分
@ # @ 符号
[\w\.-]+ # 匹配域名部分
(?#comment: 这是一个简单的 email 地址匹配正则表达式)
'''
现在让我们逐行解析这个正则表达式模式:
-
[\w\.-]+
:这部分匹配 email 地址中的用户名部分。[\w\.-]
表示匹配单个字母、数字、下划线、句点或连字符,+
表示匹配前面的字符至少一次。 -
@
:这部分匹配 email 地址中的 @ 符号。 -
[\w\.-]+
:这部分匹配 email 地址中的域名部分,规则与用户名部分相似。 -
(?#comment: 这是一个简单的 email 地址匹配正则表达式)
:这是一个注释,不会对匹配产生影响,只是用来解释正则表达式的作用。
然后我们使用 pattern.match(text)
方法尝试在给定的文本中找到匹配正则表达式模式的部分。如果找到了匹配,就会返回一个匹配对象;否则返回 None。
最后,我们检查是否找到了匹配,如果找到了,则打印匹配的部分。
在这个示例中,由于文本 "example@example.com" 符合我们定义的 email 地址模式,因此会成功匹配,并打印出 "example@example.com"。