正则表达式断言


断言

(练习网站)[https://regexlearn.com/zh-cn/learn/regex101]

正向先行断言

在正则表达式中,(?=...) 是一个正向肯定预查(positive lookahead)的语法结构。它用于在匹配字符串时,查找某个位置后面是否跟着特定的模式,而不消耗实际的字符。

具体来说,(?=PM) 匹配一个数字序列(\d+),但该数字序列后面必须紧跟着字符串 “PM”。这种预查会在匹配的时候向前看,并确定某个位置后面是否满足预期的条件。

举个例子,假设有以下文本:

12PM 3PM 6PM

如果使用正则表达式 \d+(?=PM) 进行匹配,它将匹配到以下结果:

  • “12”:在 “12” 后面紧跟着 “PM”。
  • “3”:在 “3” 后面紧跟着 “PM”。
  • “6”:在 “6” 后面紧跟着 “PM”。

需要注意的是,正向肯定预查只是用来判断某个位置后面的模式是否匹配,它并不会包含在最终的匹配结果中。因此,预查部分(即 “PM”)不会包含在匹配的结果中,只有数字序列会被捕获。

import re
res = re.findall("\d+(?=PM)", "23PM 42ji")
print(res)
# ['23'] 

负向先行断言

负向先行断言(negative lookahead)是正则表达式的一种语法结构,用于在匹配字符串时,查找某个位置后面是否不跟着特定的模式。它与负向后行断言类似,但是用于否定条件。

负向先行断言的语法结构是 (?!...),其中 ... 表示要匹配的模式。

举个例子,假设我们想匹配一个字符串中不跟着 “xyz” 的数字序列。我们可以使用负向先行断言来实现这个目标。

正则表达式:\d+(?!xyz)

这个正则表达式会匹配一个或多个数字,但要求它后面不跟着 “xyz”。下面是一些例子来说明匹配情况:

  • “123”:匹配成功,因为它后面不是 “xyz”。
  • “456xyz”:不匹配,因为 “456” 后面是 “xyz”。
  • “789abc”:匹配成功,因为 “789” 后面不是 “xyz”。

负向先行断言允许我们在匹配过程中限制某个位置后面的内容,以满足特定的条件。

import re
res = re.findall("\d+(?!PM)", "23PM 42ji")
print(res)
# ['2', '42']

负向后行断言

负向后行断言是正则表达式的一种语法结构,用于在匹配字符串时,查找某个位置前面是否不跟着特定的模式。它类似于正向肯定预查,但是用于否定条件。

假设我们想匹配一个字符串中不紧跟着 “abc” 的 “def”。我们可以使用负向后行断言来实现这个目标。

正则表达式:(?<!abc)def

这个正则表达式会匹配 “def”,但是要求它前面的三个字符不是 “abc”。下面是一些例子来说明匹配情况:

  • “def”:匹配成功,因为它前面不是 “abc”。
  • “abcdef”:不匹配,因为 “def” 前面是 “abc”。
  • “xyzdef”:匹配成功,因为 “def” 前面不是 “abc”。

负向后行断言允许我们在匹配过程中限制某个位置前面的内容,以满足特定的条件。

import re
res = re.findall(r'(?<!abc)PM', "abcPM 23pm")
print(res)
# []

正向后行断言

正向后行断言(positive lookbehind)是正则表达式的一种语法结构,用于在匹配字符串时,查找某个位置之前是否跟着特定的模式。它类似于正向肯定预查,但是用于前面的条件。

正向后行断言的语法结构是 (?<=...),其中 ... 表示要匹配的模式。

举个例子,假设我们想匹配一个字符串中紧跟着 “abc” 的 “def”。我们可以使用正向后行断言来实现这个目标。

正则表达式:(?<=abc)def

这个正则表达式会匹配 “def”,但要求它前面的三个字符是 “abc”。下面是一些例子来说明匹配情况:

  • “abcdef”:匹配成功,因为 “def” 前面是 “abc”。
  • “xyzabcdef”:不匹配,因为 “def” 前面不是 “abc”。
  • “abcxyzdef”:不匹配,因为 “def” 前面不是紧跟着 “abc”。

正向后行断言允许我们在匹配过程中限制某个位置之前的内容,以满足特定的条件。需要注意的是,断言部分(即 “abc”)不会包含在最终的匹配结果中,只有断言后面的部分会被捕获。

import re
res = re.findall("(?<=23)\w+", "23PM 42ji")
print(res)

匹配模式

贪婪匹配

正则默认贪婪匹配,意思就是匹配到第一个符合要求的以后,不会暂停,会继续匹配

懒惰匹配

匹配到第一个符合要求的就不匹配了,例如:

ber beer beeer beeeer
.*?r
只会匹配到ber,这第一个单词

与贪婪匹配不同,懒惰匹配在第一次匹配时停止。下面的例子中,在 * 之后添加 ?,将查找以 r 结尾且前面带有任意字符的第一个匹配项。这意味着本次匹配将会在第一个字母 r 处停止。

引用组

引用组(capturing group)是正则表达式中的一种语法结构,用于将匹配的内容进行分组并在后续操作中引用。引用组使用圆括号 ( ) 来定义。

当正则表达式匹配到引用组时,匹配的内容会被捕获并保存在一个特定的索引中,可以在后续的正则表达式操作或替换中使用这些引用。
例如:

ha-ha,haa-haa
(ha)-\1,(haa)-\2

\1 保存的是ha,\2保存的是haa

下面是一个使用引用组的 Python 代码示例:

import re

# 定义要匹配的字符串
text = "Hello, my name is John Doe."

# 使用引用组进行匹配和替换
pattern = r"Hello, my name is ([A-Za-z\s]+)\."
replacement = r"Nice to meet you, \1!"

# 替换匹配的内容并输出结果
result = re.sub(pattern, replacement, text)
print(result)

运行以上代码,将输出:

Nice to meet you, John Doe!

下面是 re.sub 函数的完整参数列表和用法:

re.sub(pattern, repl, string, count=0, flags=0)

pattern:要匹配的正则表达式模式。
repl:替换字符串,可以是普通字符串或一个替换函数。
string:待处理的原始字符串。
count(可选):指定替换的最大次数,默认为 0,表示全部替换。
flags(可选):用于控制正则表达式的匹配方式,例如忽略大小写、多行匹配等。

在这个例子中,我们使用引用组 ( )([A-Za-z\s]+) 匹配的内容进行了分组。这个引用组匹配一个或多个字母和空格,表示一个人的姓名。然后,我们使用 \1 来引用第一个引用组的匹配结果,将其用于替换字符串中的内容:插入到"replacement"中\1处

在替换中,我们将匹配到的内容替换为 “Nice to meet you, “ 加上引用组中捕获的姓名。因此,”Hello, my name is John Doe.” 被替换为 “Nice to meet you, John Doe!”。

通过引用组,我们可以在正则表达式中捕获并引用特定的匹配结果,从而进行更灵活的操作和替换。


Author: Acaibird
Reprint policy: All articles in this blog are used except for special statements CC BY 4.0 reprint policy. If reproduced, please indicate source Acaibird !
  TOC