Python 正则学习
正则表达式 Regular Expression 的主要功能是从字符串(string)中通过特定的模式,搜索希望找到的内容。
1. re
Python 中可以使用包 re 来处理正则表达式。
下面是一个简单的应用,目的是找到字符串中的数字:
import re
m = re.search("[0-9]", "ab5cd4ef")
print(m.group())
re.search() 接收两个参数,第一个参数 [0-9] 就是我们所说的正则表达式,它告诉 Python,听着,我想从字符串中找从 0 到 9 的任意一个数字字符。
re.search() 如果从第二个参数中找到符合要求的子字符串,就返回一个对象 m,你可以通过 m.group() 的方法查看搜索到的结果。如果没有找到符合要求的字符,则 re.search() 会返回 None。
除了 search() 方法外,re 包还提供了其他搜索方法,它们的功能有所差别:
# 搜索整个字符串,直到发现符合的子字符串,如果没有发现返回 None
m = re.search(pattern, string)
# 从头开始检查字符串是否符合正则表达式。
# 必须从字符串的第一个字符开始就相符
m = re.match(pattern, string)
我们可以从这两个函数中选择一个进行搜索。上面的例子中,如果使用 re.match() 的话,则会得到 None,因为字符串的起始为 a,不符合 [0-9] 的要求。再一次,我们可以使用 m.group() 来查看找到的字符串。
我们还可以在搜索之后将搜索到的子字符串进行替换。下面的 sub() 利用正则 pattern 在字符串 string 中进行搜索。对于搜索到的字符串,用另一个字符串 replacement 进行替换。函数将返回替换后的字符串:
str = re.sub(pattern, replacement, string)
此外,常用的方法还有
# 根据正则表达式分割字符串,将分割后的所有子字符串
# 放在一个列表(list)中返回
re.split()
# 根据正则表达式搜索字符串,将所有符合条件的子字符串
# 放在一个列表(list)中返回
re.findall()
如何写正则表达式
正则表达式的功能其实非常强大,关键在于如何写出有效的正则表达式。
我们先看正则表达式的常用语法。
正则表达式用某些符号代表单个字符:
-
.任意的一个字符
-
a|b字符
a或字符b -
[afg]a或者f或者g中的一个字符 -
[0-4]0-4范围内的一个字符 -
[a-f]a-f范围内的一个字符 -
[^m]不是
m的一个字符 -
\s一个空格
-
\S一个非空格
-
\d一个数字,相当于
[0-9] -
\D一个非数字,相当于
[^0-9] -
\w任何语言单词的一部分的字符,以及数字和下划线
-
\W匹配任何不是单词字符的字符
正则表达式还可以用某些符号来表示某种形式的重复,这些符号紧跟在单个字符之后,就表示多个这样类似的字符
-
*重复超过
0次或更多次,尽量多的匹配字符串。 -
+重复
1次或超过1次 -
?重复
0次或1次 -
{m}重复
m次。比如,a{4}相当于aaaa,再比如,[1-3]{2}相当于[1-3][1-3] -
{m, n}重复
m到n次。比如说a{2, 5}表示a重复2到5次。小于m次的重复,或者大于n次的重复都不符合条件 -
*?,+?,??*,+,和?修饰符都是贪婪的;它们在字符串进行尽可能多的匹配。有时候并不需要这种行为。如果正则式
<.*>希望找到<a> b <c>,它将会匹配整个字符串,而不仅是<a>。在修饰符之后添加
?将使样式以非贪婪方式进行匹配;尽量少的字符将会被匹配。使用正则式
<.*?>将会仅仅匹配<a> -
{m,n}?非贪婪模式,只匹配尽量少的字符次数。比如,对于
aaaaaa,a{3,5}匹配 5 个a,而a{3,5}?只匹配 3 个a。 -
|或者,
A|B,A或B,绝不贪婪
下面是重复符号的例子:
| 正则表达 | 相符的字符串举例 | 不相符字符串举例 |
|---|---|---|
[0-9]{3,5} |
"9678" |
"12" "1234567" |
a?b |
"b" "ab" "cb" |
"ac" |
a+b |
"aaaaab" |
"b" |
最后,还有位置相关的符号:
-
^字符串的起始位置
-
$字符串的结尾位置
下面是位置符号的一些例子:
正则表达 |
相符的字符串举例 |
不相符的字符串 |
|---|---|---|
^ab.*c$ |
abeec |
cabeec |
信息提取
有的时候,我们想在搜索的同时,对结果进一步提炼。比如说,我们从下面一个字符串中提取信息:
s = "abcd_output_1994_abcd_1912_abcd"
如果我们把正则表达式写成:
"output_\d{4}"
那么用 search() 方法可以找到 output_1994 。但如果我们想进一步提取出 1994 本身,则可以在正则表达式上给目标加上括号:
output_(\d{4})
括号 () 包围了一个小的正则表达式 \d{4}。这个小的正则表达式能从结果中进一步筛选信息,即四位的阿拉伯数字。用括号 () 圈起来的正则表达式的一部分,称为群(group)。一个正则表达式中可以有多个群。
我们可以 group(number) 的方法来查询群。需要注意的是,group(0) 是整个正则表达的搜索结果。group(1) 是第一个群,以此类推:
import re
m = re.search(r"output_(\d{4})", "output_1986.txt")
print(m.group(1)) # 将找到4个数字组成的1986
我们还可以将群命名,以便更好地使用 group 查询:
import re
m = re.search(r"output_(?P<year>\d{4})", "output_1986.txt") #(?P<name>...) 为group命名
print(m.group("year")) # 打印1986
上面的 (?P<year>…) 括住了一个群,并把它命名为 year。用这种方式来产生群,就可以通过 year 这个键来提取结果。
1. 正则表达式对象
以上都是直接通过正则表达式来进行操作,很多时候为了更方便应用正则表达式,会将正则表达式的样式编译为一个正则表达式对象(正则对象),可以用于匹配,通过这个对象的方法进行操作,在特定情况下使正则应用更加高效。
pattern = re.compile(r"output_(\d{4})")
pattern.search("output_1986.txt")
pattern.search("output_1986.txt").group(1)
2. 多行搜索
re.findall(r"^wo.*", "hello\nworld\nworld hello")
re.findall(r"^wo.*", "hello\nworld\nworld hello", flags=re.M)
3. 忽略大小写
re.findall(r"^wo.*", "hello\nworld\nWorld hello", flags=re.M)
re.findall(r"^wo.*", "hello\nworld\nWorld hello", flags=(re.M + re.I))