本文主要是介绍[Python 实战] - No.12 Python 中的正则表达式使用,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
1. Python中如何使用正则表达式
Python中使用正则表达式的步骤如下:
- 使用
import re
导入正则表达式模块 - 使用
re.compile()
创建一个对象 - 使用
Regex
对象的search()
方法,传入一个字符串,然后返回一个Match
对象 - 调用
Match
对象的group()
方法,返回文本中匹配该正则表达式的字符串
示例如下,查找学生姓名中姓Zhang
的同学姓名
import renamelist = "Li Ming;Zhang San;Fu yu;Guo Ji;Ren Jie;Zhang Lin;"
nameRegex = re.compile(r"Zhang\s\w+")
match = nameRegex.search(namelist)
print(match.group())
结果如下:
Zhang San
上面的代码中,有几个地方需要解释一下:
-
re.compile(r"Zhang San\s\w+")
在正则表达式的前面加了一个r,标识该字符为原始字符串。因为,在Python中,转义字符前面需要加\
来标记,如果你需要在字符串中打出\
,那么你需要使用\\
,或者在字符串的前面加入一个r
来标记r"Zhang San\s\w+"
和"Zhang San\\s\\w+"
是等价的 -
search()
函数匹配文本中第一个符合该字符串的结果并返回一个Match
对象,Match
对象的group()
函数将返回被查找到的实际文本。所以在上述结果中,我们仅得到Zhang San
这个结果。如果你的正则表达式中含有分组(后续会讲到),你可以使用group(1)
,group(2)
来查询正则表达式中第一个,第二个分组的匹配结果。
2. 正则表达式的更多模式
1. 使用括号分组
假设,某地区的电话号码的表示形式为123-456-7890
的形式,且前三位为区号,后七位标识电话号,要求将从文本中同时获取区号,电话号和整体的电话号码。
代码和结果如下:
text = "My phone number is 455-789-1234"
pnRegex = re.compile(r"(\d\d\d)-(\d\d\d-\d\d\d\d)")
match = pnRegex.search(text)
print(match.group())
print(match.group(1))
print(match.group(2))
print(match.groups())
结果如下:
455-789-1234
455
789-1234
(‘455’, ‘789-1234’)
group()
默认传入参数为0,即返回整个匹配的文本。如果想获取全体分组的结果,使用groups()
函数,该函数返回一个包含所有分组匹配结果的元组。
2. 使用管道匹配多个分组
字符|
是正则表达式中的管道,用来匹配许多表达式中的一个。如果想匹配姓名列表中,姓Zhang的和姓Li的同学的姓名,可以使用管道|
来连接多个正则表达式。
namelist1 = "Li Ming;Zhang San;Fu yu;Guo Ji;Ren Jie;Zhang Lin;"namelist2 = "Zhang San;Fu yu;Guo Ji;Ren Jie;Zhang Lin;Li Ming;"nameRegex = re.compile(r"Zhang\s\w+|Li\s\w+")match1 = nameRegex.search(namelist1)print(match1.group())match2 = nameRegex.search(namelist2)print(match2.group())
结果如下:
Li Ming
Zhang San
3. 使用问号实现可选匹配
例如在之前的电话匹配中,我们希望即便有人省略区号,依然可以检测出电话号码。使用?
来实现部分匹配的模式是可选的
text1 = "My phone number is 455-789-1234"
text2 = "My phone number is 789-1234"
pnRegex = re.compile(r"(\d\d\d-)?(\d\d\d-\d\d\d\d)")
match1 = pnRegex.search(text1)
print(match1.group())
match2 = pnRegex.search(text2)
print(match2.group())
结果如下:
455-789-1234
789-1234
4. 使用花括号匹配特定次数
假设现在我们有一串字符串:
* *** ********** ** *** ****** ** ***** * ******* ***** **** ***** * *** * **
如果我们想匹配一下几种情况:
- 恰好三个* 连在一起的,如
***
- 少于等于三个* 连在一起的,如
**
,*
- 连在一起的*个数大于等于四,但是小于等于五
- 大于等于六个*连在一起的,如
******
代码如下:
text = "* *** ********** ** **** ****** ** ***** * ******* ***** **** ***** * *** * **"
sRegex1 = re.compile(r"(\*){3}")
sRegex2 = re.compile(r"(\*){,3}")
sRegex3 = re.compile(r"(\*){4,5}")
sRegex4 = re.compile(r"(\*){6,}")
match1 = sRegex1.search(text)
match2 = sRegex2.search(text)
match3 = sRegex3.search(text)
match4 = sRegex4.search(text)
print(match1.group())
print(match2.group())
print(match3.group())
print(match4.group())
结果如下所示:
*** * ***** **********
r"(\*){3}"
中,(\*)
表示匹配*型字符的分组。因为 *在正则表达式中表示匹配一个或多个,所以需要使用\
进行转义,表示字符 *
花括号{n,m}
,表示前面的分组重复次数大于等于n次并且小于等于m次。m和n也可省略其中一个,表示大于等于n或者小于等于m。{n}
表示分组恰好重复n次。
另外,可以看到,在被匹配的文本中,长度为4的字符串****
排在长度为5的字符串*****
前面,但是代码查找到的结果是*****
,这是因为默认情况下正则表达式是贪婪地,花括号的贪婪版本会尽可能的匹配更长的字符串。使用字符?
可以声明正则表达式为非贪心形式
text = "* *** ********** ** *** ****** **** ***** * ******* ***** **** ***** * *** * **"
sRegex1 = re.compile(r"(\*){4,5}")
match1 = sRegex1.search(text)
sRegex2 = re.compile(r"(\*){4,5}?")
match2 = sRegex2.search(text)
print(match1.group())
print(match2.group())
结果如下:
***** ****
5. findall()方法
re模块的findall()
方法返回被匹配文本中的所有匹配到的结果。
之前提到的search()
仅返回文本中第一个匹配到的结果,方法返回一个Match
对象,并调用Match对象的group()函数获取匹配结果
findall()
匹配文本中所有匹配的结果,并且返回一个所有结果的列表。如果正则表达式中有分组,那么findall()
将返回分组的列表
比如之前的电话号的正则表达式:
text = "My phone number is 455-789-1234,Lily's phone number is 110-101-1230 and Lucy's phone number is 789-456-1245"
pnRegex = re.compile(r"(\d\d\d)-(\d\d\d-\d\d\d\d)")
reslist = pnRegex.findall(text)
print(reslist)
结果如下:
[(‘455’, ‘789-1234’), (‘110’, ‘101-1230’), (‘789’, ‘456-1245’)]
6. sub()函数和compile()函数
前面我们使用了re.compile()
来构造特定正则表达式的Regex
对象,compile()
函数具体的签名如下:
def compile(pattern, flags=0)
所以我们可以在compile()
追加第二个参数,实现特定功能。
例如:检索文本中所有的Alice
词语,不区分大小写,代码如下
text = "Alice is aLice,aliCe,and ALIcE.But it's not Bob."
regex = re.compile("Alice", re.IGNORECASE)
res = regex.findall(text)
print(res)
结果如下所示:
[‘Alice’, ‘aLice’, ‘aliCe’, ‘ALIcE’]
flags`的其他参数如下:
参数 | 缩写 | 用途 |
---|---|---|
re.IGNORECASE | re.I | Perform case-insensitive matching. |
re.LOCALE | re.L | Make \w, \W, \b, \B, dependent on the current locale. |
re.MULTILINE | re.M | “^” matches the beginning of lines (after a newline) as well as the string. “$” matches the end of lines (before a newline) as well as the end of the string. |
re.DOTALL | re.D | “.” matches any character at all, including the newline. |
re.VERBOSE | re.X | Ignore whitespace and comments for nicer looking RE’s. |
re.UNICODE | re.U | For compatibility only. Ignored for string patterns (it is the default), and forbidden for bytes patterns. |
sub()
函数可以用于替换正则表达式查找到的字符串。例如,我们将之前字符串中所有的Alice的姓名隐藏:
text = "Alice is aLice,aliCe,ALIcE.But it's not Bob."
regex = re.compile(r"(A)(\w+)", re.IGNORECASE)
print(regex.sub(r'\1****',text))
结果如下所示:
A**** is a****,a****,A****.But it’s not Bob.
sub()
函数第一个参数是要替换为的字符串,第二个参数是匹配的正则表达式。另外在sub()
函数的第一个参数中,可以使用\1
,\2
…来表示替换分组1,2…中的文本
正则表达式中的常用字符表,网上资源很多,这里不再放出来。
P.S. 文章不足之处还望指正
参考书籍:《Python编程快速上手—让繁琐工作自动化》
这篇关于[Python 实战] - No.12 Python 中的正则表达式使用的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!