原文: https://www.programiz.com/python-programming/regex

在本教程中,您将学习正则表达式(RegEx),并使用 Python 的re模块与 RegEx 一起使用(在示例的帮助下)。

正则表达式(RegEx)是定义搜索模式的字符序列。 例如,

  1. ^a...s$

上面的代码定义了 RegEx 模式。 模式为从as的任何五个字母的字符串。

使用 RegEx 定义的模式可用于与字符串匹配。

表达式 字符串 是否匹配
^a...s$ abs 没有匹配
alias 匹配
abyss 匹配
Alias 没有匹配
An abacus 没有匹配

Python 有一个名为re的模块可与 RegEx 一起使用。 这是一个例子:

  1. import re
  2. pattern = '^a...s$'
  3. test_string = 'abyss'
  4. result = re.match(pattern, test_string)
  5. if result:
  6. print("Search successful.")
  7. else:
  8. print("Search unsuccessful.")

在这里,我们使用re.match()函数在test_string中搜索pattern。 如果搜索成功,该方法将返回一个匹配对象。 如果不是,则返回None


re模块中定义了其他一些函数,可与 RegEx 一起使用。 在探讨之前,让我们学习正则表达式本身。

如果您已经了解 RegEx 的基础知识,请跳至 Python RegEx


使用 RegEx 指定模式

为了指定正则表达式,使用了元字符。 在上面的示例中,^$是元字符。


元字符

元字符是 RegEx 引擎以特殊方式解释的字符。 以下是元字符列表:

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

[] - 方括号

方括号指定您要匹配的一组字符。

表达式 字符串 是否匹配
[abc] a 1 个匹配
ac 2 个匹配
Hey Jude 没有匹配
abc de ca 5 个匹配

在这里,如果您要匹配的字符串包含abc中的任何一个,则[abc]将匹配。

您也可以使用方括号内的-指定字符范围。

  • [a-e][abcde]相同。
  • [1-4][1234]相同。
  • [0-39][01239]相同。

您可以在方括号的开头使用尖号^符号来补充(反转)字符集。

  • [^abc]表示除abc之外的任何字符。
  • [^0-9]表示任何非数字字符。

. - 句号

句点匹配任何单个字符(换行符'\n'除外)。

表达式 字符串 是否匹配
.. a 没有匹配
ac 1 个匹配
acd 1 个匹配
acde 2 个匹配(包含 4 个字符)

^ - 脱字符

插入符号^用于检查字符串是否以某个字符开头

表达式 字符串 是否匹配
^a a 1 个匹配
abc 1 个匹配
bac 没有匹配
^ab abc 1 个匹配
acb 没有匹配(以a开头,但之后没有b

$ - 美元

美元符号$用于检查字符串是否以某个字符结束

表达式 字符串 是否匹配
a$ a 1 个匹配
formula 1 个匹配
cab 没有匹配

* - 星号

星形符号*匹配模式的零次或多次出现

表达式 字符串 是否匹配
ma*n mn 1 个匹配
man 1 个匹配
maaan 1 个匹配
main 没有匹配(a之后没有n
woman 1 个匹配

+- 加号

加号+匹配左侧的模式的一个或多个出现

表达式 字符串 是否匹配
ma+n mn 没有匹配(没有a字符)
man 1 个匹配
maaan 1 个匹配
main 没有匹配(a后跟n
woman 1 个匹配

? - 问号

问号符号?匹配模式的零或一次出现

表达式 字符串 是否匹配
ma?n mn 1 个匹配
man 1 个匹配
maaan 没有匹配(一个以上a字符)
main 没有匹配(a之后没有n
woman 1 个匹配

{} - 大括号

考虑以下代码:{n,m}。 这意味着至少n,并且最多m个重复的模式留给它。

表达式 字符串 是否匹配
a{2,3} abc dat 没有匹配
abc daat 1 个匹配(在d<u>aa</u>t
aabc daaat 2 个匹配(在<u>aa</u>bcd<u>aaa</u>t
aabc daaaat 2 个匹配(在<u>aa</u>bcd<u>aaa</u>at

让我们再尝试一个示例。 此 RegEx [0-9]{2, 4}匹配至少 2 位但不超过 4 位

表达式 字符串 是否匹配
[0-9]{2,4} ab123csde 1 个匹配(在ab<u>123</u>csde
12 and 345673 3 个匹配(<u>12</u><u>3456</u><u>73</u>
1 and 2 没有匹配

| - 替代项

竖线|用于交替(or运算符)。

表达式 字符串 是否匹配
a&#124;b cde 没有匹配
ade 1 个匹配(在<u>a</u>de匹配)
acdbea 3 个匹配(在<u>a</u>cd<u>b</u>e<u>a</u>

在此,a|b匹配包含ab的任何字符串


() - 分组

括号()用于对子模式进行分组。 例如,(a|b|c)xz匹配与abc匹配的任何字符串,后跟xz

表达式 字符串 是否匹配
(a&#124;b&#124;c)xz ab xz 没有匹配
abxz 1 个匹配(在a<u>bxz</u>匹配)
axz cabxz 2 个匹配(在<u>axz</u>bc ca<u>bxz</u>

\ - 反斜线

反冲\用于转义包括所有元字符在内的各种字符。 例如,

如果字符串包含$后跟a,则\$a匹配。 在这里,$不是由 RegEx 引擎以特殊方式解释的。

如果不确定某个字符是否具有特殊含义,可以在其前面放置\。 这样可以确保不对字符进行特殊处理。


特殊序列

特殊序列使常用模式更易于编写。 以下是特殊序列的列表:

\A - 如果指定字符在字符串的开头,则匹配。

表达式 字符串 是否匹配
\Athe the sun 匹配
In the sun 没有匹配

\b - 如果指定字符在单词的开头或结尾,则匹配。

表达式 字符串 是否匹配
\bfoo football 匹配
a football 匹配
afootball 没有匹配
foo\b the foo 匹配
the afoo test 匹配
the afootest 没有匹配

\B - 与\b相反。 如果指定字符不是单词开头或结尾,则匹配。

表达式 字符串 是否匹配
\Bfoo football 没有匹配
a football 没有匹配
afootball 匹配
foo\B the foo 没有匹配
the afoo test 没有匹配
the afootest 匹配

\d - 匹配任何十进制数字。 相当于[0-9]

表达式 字符串 是否匹配
\d 12abc3 3 个匹配(在<u>12</u>abc<u>3</u>
Python 没有匹配

\D - 匹配任何非十进制数字。 相当于[^0-9]

表达式 字符串 是否匹配
\D 1ab34"50 3 个匹配(在1<u>ab</u>34<u>"</u>50
1345 没有匹配

\s - 匹配字符串包含任何空格字符的地方。 等效于[ \t\n\r\f\v]

表达式 字符串 是否匹配
\s Python RegEx 1 个匹配
PythonRegEx 没有匹配

\S - 匹配字符串包含任何非空白字符的地方。 等效于[^ \t\n\r\f\v]

表达式 字符串 是否匹配
\S a b 2 个匹配(在<u>a</u> <u>b</u>
没有匹配

\w - 匹配任何字母数字字符(数字和字母)。 等效于[a-zA-Z0-9_]。 顺便说一下,下划线_也被认为是字母数字字符。

表达式 字符串 是否匹配
\w 12&": ;c 3 个匹配(在<u>12</u>&": ;<u>c</u>
%"> ! 没有匹配

\W - 匹配任何非字母数字字符。 相当于[^a-zA-Z0-9_]

表达式 字符串 是否匹配
\W 1a2%c 1 个匹配(在1<u>a</u>2<u>%</u>c
Python 没有匹配

\Z - 如果指定字符在字符串的末尾,则匹配。

表达式 字符串 是否匹配
Python\Z I like Python 1 个匹配
I like Python Programming 没有匹配
Python is fun. 没有匹配

提示:要构建和测试正则表达式,可以使用 RegEx 测试器工具,例如 regex101 。 该工具不仅可以帮助您创建正则表达式,还可以帮助您学习它。

现在,您了解了 RegEx 的基础知识,让我们讨论如何在 Python 代码中使用 RegEx。


Python RegEx

Python 有一个名为re的模块可用于正则表达式。 要使用它,我们需要导入模块。

  1. import re

该模块定义了一些可与 RegEx 一起使用的函数和常量。


re.findall()

re.findall()方法返回包含所有匹配项的字符串列表。


示例 1:re.findall()

  1. # Program to extract numbers from a string
  2. import re
  3. string = 'hello 12 hi 89\. Howdy 34'
  4. pattern = '\d+'
  5. result = re.findall(pattern, string)
  6. print(result)
  7. # Output: ['12', '89', '34']

如果找不到该模式,则re.findall()返回一个空列表。


re.split()

re.split方法在存在匹配项的地方拆分字符串,并返回发生拆分的字符串列表。


示例 2:re.split()

  1. import re
  2. string = 'Twelve:12 Eighty nine:89.'
  3. pattern = '\d+'
  4. result = re.split(pattern, string)
  5. print(result)
  6. # Output: ['Twelve:', ' Eighty nine:', '.']

如果找不到该模式,则re.split()返回一个包含原始字符串的列表。


您可以将maxsplit参数传递给re.split()方法。 这是将要发生的最大拆分次数。

  1. import re
  2. string = 'Twelve:12 Eighty nine:89 Nine:9.'
  3. pattern = '\d+'
  4. # maxsplit = 1
  5. # split only at the first occurrence
  6. result = re.split(pattern, string, 1)
  7. print(result)
  8. # Output: ['Twelve:', ' Eighty nine:89 Nine:9.']

顺便说一下,maxsplit的默认值为 0; 意味着所有可能的分裂。


re.sub()

re.sub()的语法为:

  1. re.sub(pattern, replace, string)

该方法返回一个字符串,其中匹配的匹配项被replace变量的内容替换。


示例 3:re.sub()

  1. # Program to remove all whitespaces
  2. import re
  3. # multiline string
  4. string = 'abc 12\
  5. de 23 \n f45 6'
  6. # matches all whitespace characters
  7. pattern = '\s+'
  8. # empty string
  9. replace = ''
  10. new_string = re.sub(pattern, replace, string)
  11. print(new_string)
  12. # Output: abc12de23f456

如果找不到该模式,则re.sub()返回原始字符串。


您可以将count作为第四个参数传递给re.sub()方法。 如果省略,则结果为 0。这将替换所有出现的事件。

  1. import re
  2. # multiline string
  3. string = 'abc 12\
  4. de 23 \n f45 6'
  5. # matches all whitespace characters
  6. pattern = '\s+'
  7. replace = ''
  8. new_string = re.sub(r'\s+', replace, string, 1)
  9. print(new_string)
  10. # Output:
  11. # abc12de 23
  12. # f45 6

re.subn()

re.subn()re.sub()相似,但期望它返回 2 个项目的元组,其中包含新字符串和进行的替换数目。


示例 4:re.subn()

  1. # Program to remove all whitespaces
  2. import re
  3. # multiline string
  4. string = 'abc 12\
  5. de 23 \n f45 6'
  6. # matches all whitespace characters
  7. pattern = '\s+'
  8. # empty string
  9. replace = ''
  10. new_string = re.subn(pattern, replace, string)
  11. print(new_string)
  12. # Output: ('abc12de23f456', 4)

re.search()

re.search()方法采用两个参数:模式和字符串。 该方法查找 RegEx 模式与字符串匹配的第一个位置。

如果搜索成功,则re.search()返回一个匹配对象。 如果不是,则返回None

  1. match = re.search(pattern, str)

示例 5:re.search()

  1. import re
  2. string = "Python is fun"
  3. # check if 'Python' is at the beginning
  4. match = re.search('\APython', string)
  5. if match:
  6. print("pattern found inside the string")
  7. else:
  8. print("pattern not found")
  9. # Output: pattern found inside the string

在此,match包含一个匹配对象。


匹配对象

您可以使用dir()函数获取匹配对象的方法和属性。

匹配对象的一些常用方法和属性是:


match.group()

group()方法返回字符串中匹配的部分。

示例 6:匹配对象

  1. import re
  2. string = '39801 356, 2102 1111'
  3. # Three digit number followed by space followed by two digit number
  4. pattern = '(\d{3}) (\d{2})'
  5. # match variable contains a Match object.
  6. match = re.search(pattern, string)
  7. if match:
  8. print(match.group())
  9. else:
  10. print("pattern not found")
  11. # Output: 801 35

在此,match变量包含一个匹配对象。

我们的模式(\d{3}) (\d{2})具有两个子组(\d{3})(\d{2})。 您可以获取这些带括号的子组的字符串的一部分。 这是如何做:

  1. >>> match.group(1)
  2. '801'
  3. >>> match.group(2)
  4. '35'
  5. >>> match.group(1, 2)
  6. ('801', '35')
  7. >>> match.groups()
  8. ('801', '35')

match.start()match.end()match.span()

start()函数返回匹配的子字符串的开头的索引。 同样,end()返回匹配的子字符串的结束索引。

  1. >>> match.start()
  2. 2
  3. >>> match.end()
  4. 8

span()函数返回一个包含匹配部分的开始和结束索引的元组。

  1. >>> match.span()
  2. (2, 8)

match.rematch.string

匹配对象的re属性返回正则表达式对象。 同样,string属性返回传递的字符串。

  1. >>> match.re
  2. re.compile('(\\d{3}) (\\d{2})')
  3. >>> match.string
  4. '39801 356, 2102 1111'

我们已经介绍了re模块中定义的所有常用方法。 如果您想了解更多信息,请访问 Python 3 re模块


在 RegEx 之前使用r前缀

在正则表达式前使用rR前缀时,表示原始字符串。 例如,'\n'是换行,而r'\n'表示两个字符:反斜杠\后跟n

反冲\用于转义包括所有元字符在内的各种字符。 但是,使用r前缀会使\被视为正常字符。


示例 7:使用r前缀的原始字符串

  1. import re
  2. string = '\n and \r are escape sequences.'
  3. result = re.findall(r'[\n\r]', string)
  4. print(result)
  5. # Output: ['\n', '\r']