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))