Python - 正则表达式



正则表达式是一个特殊的字符序列,可帮助您使用模式中包含的专用语法匹配或查找其他字符串或字符串集。正则表达式通常称为 regex regexp

通常,字符串搜索算法使用此类模式对字符串执行“查找”或“查找和替换”操作,或用于输入验证。

数据科学项目中的大规模文本处理需要处理文本数据。包括 Python 在内的许多编程语言都支持正则表达式处理。Python 的标准库有 re 模块用于此目的。

由于 re 模块中定义的大多数函数都使用原始字符串,因此我们首先了解原始字符串是什么。

原始字符串

正则表达式使用反斜杠字符 ('\') 来表示特殊形式或允许使用特殊字符而不调用其特殊含义。另一方面,Python 使用与转义字符相同的字符。因此 Python 使用原始字符串表示法。

如果字符串在引号前以 r 或 R 为前缀,则字符串将成为原始字符串。因此 'Hello' 是一个普通字符串,而 r'Hello' 是一个原始字符串。


>>> normal="Hello"
>>> print (normal)
Hello
>>> raw=r"Hello"
>>> print (raw)
Hello

在正常情况下,两者之间没有区别。但是,当转义字符嵌入到字符串中时,普通字符串实际上会解释转义序列,而原始字符串不会处理转义字符。


>>> normal="Hello\nWorld"
>>> print (normal)
Hello
World
>>> raw=r"Hello\nWorld"
>>> print (raw)
Hello\nWorld

在上面的例子中,当打印普通字符串时,处理转义字符 '\n' 以引入换行符。但是,由于原始字符串运算符 'r' ,转义字符的效果不会根据其含义进行转换。

元字符

大多数字母和字符将简单地匹配自身。但是,某些字符是特殊的元字符,与自身不匹配。元字符是具有特殊含义的字符,类似于通配符中的 *。

以下是元字符的完整列表 -


. ^ $ * + ? { } [ ] \ | ( )

方括号符号 [ ] 表示要匹配的一组字符。字符可以单独列出,也可以作为一系列字符列出,用 '-' 分隔它们。

元字符 描述
[abc] 匹配任何字符 A、B 或 C
[a-c] 它使用 range 来表示同一组字符。
[a-z] 仅匹配小写字母。
[0-9] 仅匹配数字。
'^' 补充 [] 中的字符集。[^5] 将匹配除 '5' 之外的任何字符。

'\'是一个转义元字符。当后面跟着各种字符时,它会形成各种特殊序列。如果需要匹配 [ 或 \,可以在它们前面加上反斜杠以消除它们的特殊含义:\[ 或 \\。

下面列出了由以 '\' 开头的此类特殊序列表示的预定义字符集 -

元字符 描述
\d 匹配任何十进制数字;这相当于类 [0-9]。
\D 匹配任何非数字字符;这相当于类 [^0-9]。
\s 匹配任何空白字符;这相当于类 [\t\n\r\f\v]。
\S 匹配任何非空白字符;这相当于类 [^\t\n\r\f\v]。
\w 匹配任何字母数字字符;这相当于类 [a-zAZ0-9_]。
\W 匹配任何非字母数字字符。等效于类 [^a-zAZ0-9_]。
. 与除换行符 '\n' 之外的任何单个字符匹配。
? 匹配其左侧出现的模式 0 或 1 次
+ 模式在其左侧出现 1 次或多次
* 模式在其左侧出现 0 个或多个
\b 单词和非单词以及 /B 之间的边界与 /B 相反
[..] 匹配方括号中的任何单个字符,[^..] 匹配方括号中不带的任意单个字符。
\ 用于特殊含义的字符,如 \。匹配句点,或匹配加号的 \+。
{n,m} 匹配前面的至少 n 个和最多 m 个匹配项
a|b 匹配 a 或 b

Python 的 re 模块提供了有用的函数,用于查找匹配项、搜索模式以及将匹配的字符串替换为其他字符串等。

re.match() 函数

此函数尝试将字符串开头的 RE 模式与可选标志匹配。以下是此函数的语法 -


re.match(pattern, string, flags=0)

以下是参数的描述 -

参数 描述
pattern 这是要匹配的正则表达式。
String 这是字符串,将搜索该字符串以匹配字符串开头的模式。
Flags 您可以使用按位 OR (|) 指定不同的标志。这些是修饰符,如下表所示。

re.match() 函数在成功时返回 match 对象,失败时返回 Nonematch 对象实例包含有关匹配项的信息:匹配项的开始和结束位置、匹配的子字符串等。

match 对象的 start() 方法返回字符串中 pattern 的起始位置,end() 返回端点。

如果未找到模式,则匹配对象为 None。

我们使用 match 对象的 group(num)groups() 函数来获取匹配的表达式。

匹配对象方法 描述
group(num=0) 此方法返回整个匹配项(或特定子组 num)
groups() 此方法返回 Tuples 中所有匹配的子组(如果没有,则为空)


import re
line = "Cats are smarter than dogs"
matchObj = re.match( r'Cats', line)
print (matchObj.start(), matchObj.end())
print ("matchObj.group() : ", matchObj.group())

它将产生以下输出 -

0 4
matchObj.group() : Cats

re.search() 函数

此函数使用可选标志搜索字符串中首次出现的 RE 模式。以下是此函数的语法 -


re.search(pattern, string, flags=0)

以下是参数的描述 -

参数 描述
Pattern 这是要匹配的正则表达式。
String 这是字符串,将搜索该字符串以匹配字符串中任意位置的模式。
Flags 您可以使用按位 OR (|) 指定不同的标志。这些是修饰符,如下表所示。

re.search 函数在成功时返回 match 对象,在失败时返回 none。我们使用 match 对象的 group(num) groups() 函数来获取匹配的表达式。

匹配对象方法 描述
group(num=0) 此方法返回整个匹配项(或特定子组 num)
groups() 此方法返回 Tuples 中所有匹配的子组(如果没有,则为空)


import re
line = "Cats are smarter than dogs"
matchObj = re.search( r'than', line)
print (matchObj.start(), matchObj.end())
print ("matchObj.group() : ", matchObj.group())

它将产生以下输出 -

17 21
matchObj.group() : than

匹配 VS 搜索

Python 提供了两种基于正则表达式的不同原始操作,match 仅在字符串的开头检查匹配项,而 search 检查字符串中任何位置的匹配项(这是 Perl 默认所做的)。


import re
line = "Cats are smarter than dogs";
matchObj = re.match( r'dogs', line, re.M|re.I)
if matchObj:
	 	print ("match --> matchObj.group() : ", matchObj.group())
else:
	 	print ("No match!!")
searchObj = re.search( r'dogs', line, re.M|re.I)
if searchObj:
	 	print ("search --> searchObj.group() : ", searchObj.group())
else:
	 	print ("Nothing found!!")

执行上述代码时,它会生成以下输出 -

No match!!
search --> matchObj.group() : dogs

re.findall() 函数

findall() 函数以字符串或元组列表的形式返回字符串中 pattern 的所有不重叠匹配项。从左到右扫描字符串,并按找到的顺序返回匹配项。结果中包含空匹配项。

语法


re.findall(pattern, string, flags=0)

参数

参数 描述
Pattern 这是要匹配的正则表达式。
String 这是字符串,将搜索该字符串以匹配字符串中任意位置的模式。
Flags 您可以使用按位 OR (|) 指定不同的标志。这些是修饰符,如下表所示。


import re
string="Simple is better than complex."
obj=re.findall(r"ple", string)
print (obj)

它将产生以下输出 -

['ple', 'ple']

以下代码在 findall() 函数的帮助下获取句子中的单词列表。


import re
string="Simple is better than complex."
obj=re.findall(r"\w*", string)
print (obj)

它将产生以下输出 -

['Simple', '', 'is', '', 'better', '', 'than', '', 'complex', '', '']

re.sub() 函数

使用正则表达式的最重要的 re 方法之一是 sub。

语法


re.sub(pattern, repl, string, max=0)

此方法将 string 中 RE 模式的所有匹配项替换为 repl,除非提供 max,否则将替换所有匹配项。此方法返回修改后的字符串。


import re
phone = "2004-959-559 # This is Phone Number"

# Delete Python-style comments
num = re.sub(r'#.*$', "", phone)
print ("Phone Num : ", num)

# Remove anything other than digits
num = re.sub(r'\D', "", phone)
print ("Phone Num : ", num)

它将产生以下输出 -

Phone Num : 2004-959-559
Phone Num : 2004959559

以下示例使用 sub() 函数将所有出现的 is 替换为 was word −


import re
string="Simple is better than complex. Complex is better than complicated."
obj=re.sub(r'is', r'was',string)
print (obj)

它将产生以下输出 -

Simple was better than complex. Complex was better than complicated.

re.compile() 函数

compile() 函数将正则表达式模式编译为正则表达式对象,该对象可以使用其 match()、search() 和其他方法进行匹配。

语法


re.compile(pattern, flags=0)

标识

修饰符 描述
re.I 执行不区分大小写的匹配。
re.L 根据当前区域设置解释单词。这种解释会影响字母组(\w 和 \W)以及单词边界行为(\b 和 \B)。
re. M 使 $ 匹配行尾 (不仅仅是字符串的末尾) ,使 ^ 匹配任何行的开头 (不仅仅是字符串的开头) 。
re.S 使句点(点)匹配任何字符,包括换行符。
re.U 根据 Unicode 字符集解释字母。此标志会影响 \w, \W, \b, \B 的行为
re.X 允许 “cuter” 正则表达式语法。它忽略空格(除了在集合 [] 内或用反斜杠转义时),并将未转义的 # 视为注释标记。

序列 -


prog = re.compile(pattern)
result = prog.match(string)

等效于 −


 result = re.match(pattern, string)

但是,当表达式将在单个程序中多次使用时,使用 re.compile() 并保存生成的正则表达式对象以供重用会更有效。


import re
string="Simple is better than complex. Complex is better than complicated."
pattern=re.compile(r'is')
obj=pattern.match(string)
obj=pattern.search(string)
print (obj.start(), obj.end())

obj=pattern.findall(string)
print (obj)

obj=pattern.sub(r'was', string)
print (obj)

它将产生以下输出 -

7 9
['is', 'is']
Simple was better than complex. Complex was better than complicated.

re.finditer() 函数

此函数返回一个迭代器,该迭代器在 string 中 RE 模式的所有非重叠匹配项上生成匹配对象。

语法


re.finditer(pattern, string, flags=0)


import re
string="Simple is better than complex. Complex is better than complicated."
pattern=re.compile(r'is')
iterator = pattern.finditer(string)
print (iterator )

for match in iterator:
	 	print(match.span())

它将产生以下输出 -

(7, 9)
(39, 41)

Python Regex 的示例

查找所有副词

findAll() 匹配模式的所有匹配项,而不仅仅是像 search() 那样匹配第一个匹配项。例如,如果作者想要查找某些文本中的所有副词,他们可能会按以下方式使用 findall() -


import re
text = "He was carefully disguised but captured quickly by police."
obj = re.findall(r"\w+ly\b", text)
print (obj)

它将产生以下输出 -

['carefully', 'quickly']

查找以元音开头的单词


import re
text = 'Errors should never pass silently. Unless explicitly silenced.'
obj=re.findall(r'\b[aeiouAEIOU]\w+', text)
print (obj)

它将产生以下输出 -

['Errors', 'Unless', 'explicitly']

正则表达式修饰符:选项标志

正则表达式文本可以包括一个可选修饰符,用于控制匹配的各个方面。修饰符指定为可选标志。您可以使用异 OR (|) 提供多个修饰符,如前所述,并且可以由以下修饰符之一表示 -

修饰符 描述
re.I 执行不区分大小写的匹配。
re.L 根据当前区域设置解释单词。这种解释会影响字母组(\w 和 \W)以及单词边界行为(\b 和 \B)。
re.M 使 $ 匹配行尾 (不仅仅是字符串的末尾) ,使 ^ 匹配任何行的开头 (不仅仅是字符串的开头) 。
re.S 使句点(点)匹配任何字符,包括换行符。
re.U 根据 Unicode 字符集解释字母。此标志会影响 \w, \W, \b, \B 的行为。
re.X 允许 “cuter” 正则表达式语法。它忽略空格(除了在集合 [] 内或用反斜杠转义时),并将未转义的 # 视为注释标记。

正则表达式模式

除控制字符 (+ ? . * ^ $ ( ) [ ] { } | \) 外,所有字符都与自身匹配。您可以通过在控制字符前面加上反斜杠来转义该字符。

下表列出了 Python 中可用的正则表达式语法 -

语法 描述
^ 匹配行首。
$ 匹配行尾。
. 匹配除换行符之外的任何单个字符。使用 m 选项也可以匹配换行符。
[...] 匹配方括号中的任何单个字符。
[^...] 匹配不在括号中的任何单个字符
re* 匹配前面表达式的 0 个或多个匹配项。
re+ 匹配前面表达式的 1 个或多个匹配项。
re? 匹配前面表达式的 0 次或 1 次出现。
re{ n} 与前面的表达式的 n 次出现完全匹配。
re{ n,} 匹配前面表达式的 n 个或多个匹配项。
re{ n, m} 匹配前面表达式的至少 n 次和最多 m 次出现。
a|b 匹配 a 或 b。
(re) 对正则表达式进行分组并记住匹配的文本。
(?imx) 在正则表达式中临时切换 i、m 或 x 选项。如果在括号中,则仅影响该区域。
(?-imx) 暂时关闭正则表达式中的 i、m 或 x 选项。如果在括号中,则仅影响该区域。
(?: re) 对正则表达式进行分组,而不记住匹配的文本。
(?imx: re) 暂时切换括号内的 i、m 或 x 选项。
(?-imx: re) 暂时关闭括号内的 i、m 或 x 选项。
(?#...) 评论。
(?= re) 使用阵列指定位置。没有范围。
(?! re) 使用模式否定指定位置。没有范围。
(?> re) 匹配独立模式,无回溯。
\w 匹配单词字符。
\W 匹配非单词字符。
\s 匹配空格。相当于 [\t\n\r\f]。
\S 匹配非空格。
\d 匹配数字。等效于 [0-9]。
\D 匹配非数字。
\A 匹配字符串的开头。
\Z 匹配字符串的结尾。如果存在换行符,则它在换行符之前匹配。
\z 匹配字符串的结尾。
\G 匹配上次匹配结束的点。
\b 在括号外时匹配单词边界。在括号内时匹配退格 (0x08)。
\B 匹配非单词边界。
\n, \t, etc. 匹配换行符、回车符、制表符等。
\1...\9 匹配第 n 个分组的子表达式。
\10 如果已匹配,则匹配第 n 个分组的子表达式。否则,指字符代码的八进制表示形式。

正则表达式示例

文本字符

示例 描述
python 匹配 “python”。

字符类

示例 描述
[Pp]ython 匹配 “Python” 或 “python”
rub[ye] 匹配 “ruby” 或 “rube”
[aeiou] 匹配任意一个小写元音
[0-9] 匹配任何数字;与 [0123456789] 相同
[a-z] 匹配任何小写 ASCII 字母
[A-Z] 匹配任何大写 ASCII 字母
[a-zA-Z0-9] 匹配以上任何一项
[^aeiou] 匹配除小写元音以外的任何内容
[^0-9] 匹配除数字以外的任何内容

特殊字符类

示例 描述
. 匹配除换行符之外的任何字符
\d 匹配一位数字:[0-9]
\D 匹配非数字:[^0-9]
\s 匹配空白字符:[ \t\r\n\f]
\S 匹配非空格:[^ \t\r\n\f]
\w 匹配单个单词字符:[A-Za-z0-9_]
\W 匹配非单词字符:[^A-Za-z0-9_]

重复情况

示例 描述
ruby? 匹配 “rub” 或 “ruby”:y 是可选的
ruby* 匹配 “rub” 加 0 个或多个 ys
ruby+ 匹配 “rub” 加 1 个或多个 ys
\d{3} 精确匹配 3 位数字
\d{3,} 匹配 3 个或更多数字
\d{3,5} 匹配 3 位、4 位或 5 位数字

非贪婪重复

这与最小的重复次数匹配 -

示例 描述
<.*> 贪婪重复:匹配 “<python>perl>”
<.*?> 贪婪重复:匹配 “<python>” 中的 “<python>perl>"

使用括号分组

示例 描述
\D\d+ 无组:+重复 \d
(\D\d)+ 分组:+重复 \D\d 对
([Pp]ython(, )?)+ 分组:+重复 \D\d 对

反向引用

这将再次匹配之前匹配的组 -

示例 描述
([Pp])ython&\1ails 匹配 python&pails 或 python&pails
(['"])[^\1]*\1 单引号或双引号字符串。\1 匹配第 1 组匹配的任何内容。\2 匹配第 2 组匹配的任何内容,依此类推。

选择

示例 描述
python|perl 匹配 “python” 或 “perl”
rub(y|le)) 匹配 “ruby” 或 “ruble”
Python(!+|\?) “Python” 后跟一个或多个 !或 ?

这需要指定 match 位置。

示例 描述
^Python 在字符串或内部行的开头匹配 “Python”
Python$ 匹配字符串或行末尾的 “Python”
\APython 在字符串的开头匹配 “Python”
Python\Z 匹配字符串末尾的 “Python”
\bPython\b 在单词边界处匹配 “Python”
\brub\B \B 是非单词边界:匹配 “rube” 和 “ruby” 中的 “rub”,但不能单独匹配
Python(?=!) 如果后跟感叹号,则匹配 “Python”。
Python(?!!) 匹配 “Python”,如果后面没有感叹号。

带括号的特殊语法

示例 描述
R(?#comment) 匹配 “r”。其余的都是评论
R(?i)uby 匹配 “uby” 时不区分大小写
R(?i:uby) 同上
rub(?:y|le)) 仅分组而不创建 \1 反向引用