python——正则表达式

  • Post author:
  • Post category:python

一正则表达式的引入

#需求:封装一个功能,判断用户输入的手机号码是否合法?
def checkPhone(phone):
    if len(phone) != 11:
        print('手机号码不是十一位')
        return
    if phone[0] != '1':
        print('手机号码开头不是1')
        return
    if not phone.isdigit():
        print('手机号码不是全部是数字')
        return
    print('该手机号码是正确的')
    checkPhone(112233)

使用正则表达式:

import re#需要引用re模块

result = re.search("^1\d{10}$", "12345678901")#^ 表示从什么开始(^1表示从1开始) \d表示0~9之间的数字   {10}表示出现次数为10位$结束
if result:
    print('手机号码合法')
else:
    print('手机号码不合法')
输出:
手机号码合法

二正则表达式的介绍和查找

正则表达式:是一个特殊的字符序列,通常用来检索,替换那些符合某个模式(规则)的文本
在python中需要通过正则表达式对字符串进行匹配的时候,可以使用re模块。re模块使python语言拥有全部的正则表达式功能。
应用场景:
爬虫
验证手机号码,身份证号码邮箱等
数据分析的数据清洗或者整理

\d 表示0~9之间的任意数字
+ 表示可以出现一次或者多次

正则表达式中使用 \ 作为转义字符,如果需要匹配文本中的字符 \ ,则使用编程语言表示的正则表达式里需要4个反斜杠 \ :前两个和后两个分别用于在编程语言里转义成反斜杠,转换成反斜杠后再在正则表达式里转义成一个反斜杠。

(1)正则表达式的分组

#匹配0-100数字
n = '100'
result = re.match(r'[1-9]?\d?$|100$', n)#|  表示或者
print(result)#<re.Match object; span=(0, 3), match='100'>
#验证邮箱  163  126 qq
email = '1234568@qq.com'
result = re.match(r'\w{5,20}@(163|126|qq)\.(com|cn)$', email)#(word|word|word) 表示或者  [abc]表示一个字母而不是一个单词
print(result)#<re.Match object; span=(0, 14), match='1234568@qq.com'>

result.group()获取组中匹配内容
相关方法:
起名方式:(?P<名字>正则) (?P=名字)
不需要引用分组内容:

msg = '<html><h1>abc</h1>'
msg1 = '<h1>hello</h1>'
result = re.match(r'<[0-9a-zA-Z]+>(.+)</[0-9a-zA-Z]+', msg)
print(result)#  输出:<re.Match object; span=(0, 17), match='<html><h1>abc</h1'>
print(result.group(1))#输出:<h1>abc

需要引用分组匹配的内容
1、number \number 引用第number组的数据

msg = '<html><h1>abc</h1></html>'
result = re.match(r'<([0-9a-zA-Z]+)><([0-9a-zA-Z]+)>(.+)</\2></\1>$', msg)
print(result)#<re.Match object; span=(0, 25), match='<html><h1>abc</h1></html>'>

2、?P<名字>

msg = '<html><h1>abc</h1></html>'
result = re.match(r'<(?P<name1>\w+)><(?P<name2>\w+)>(.+)</(?P=name2)></(?P=name1)>', msg)
print(result)#<re.Match object; span=(0, 25), match='<html><h1>abc</h1></html>'>
print(result.group(1))#html

(2)正则表达式查找常用的函数

re.match(匹配字符串是否以指定的正则内容开头)
re.search(扫描整个字符串,找到第一个匹配)
re.findall(扫描整个字符串,找到所有的匹配)
re.finditer(扫描整个字符串,找到所有匹配的,并返回一个可迭代对象)
re.sub(正则表达式,‘新内容’, string)(扫描整个字符串,新内容替换正则内容指定的内容)
re.split(在字符串中搜素,对指定的内容进行分割)

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

匹配成功返回对象,匹配失败返回None

pattern:匹配的正则表达式
string:要匹配(验证)的字符串
flags: 标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多 行匹配等

可以使用group(num)函数来获取匹配的表达式, group()用来提出分组截获的字符串

import re
print(re.match("\d+", "123asd"))#验证成功后返回的对象<re.Match object; span=(0, 3), match='123'>
print(re.match("\d+", "hello12345"))

result1 = re.match(r'H', 'Hello')
result2 = re.match(r'e', 'Hello')
print(result1.group(0))#'H'p匹配到的元素
print(result1.span())#(0, 1)匹配到的元素所在位置
print(result2)

输出:
<re.Match object; span=(0, 3), match='123'>
None
H
(0, 1)
None

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

匹配成功返回对象,匹配失败返回None

import re
print(re.search('\d+', '123asd98'))#<re.Match object; span=(0, 3), match='123'>
print(re.search('\d+', 'hello12345'))
result1 = re.search(r'He', 'Hello')
result2 = re.search(r'lo', 'Hello')
print(result1.group(0))
print(result1.span())
print(result2.group(0))
print(result2.span())

输出:
<re.Match object; span=(0, 3), match='123'>
<re.Match object; span=(5, 10), match='12345'>
He
(0, 2)
lo
(3, 5)

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

在字符串中找到正则表达式所匹配的所有子串,并返回一个列表,如果没有找到匹配的,则返回空列表。
注意: match 和 search 是匹配一次 findall 匹配所有。

ret = re.findall('\d+', 'he23ll34')
print(ret)
ret = re.match('\d+', 'he23ll34')
print(ret)
ret = re.search('\d+', 'he23ll34')
print(ret)

msg = 'abcd7v jkfd8hdf00'
result = re.search('[a-z][0-9][a-z]', msg)#  只要有1个匹配的后面就不会继续检索
print(result.group())#d7v
result = re.findall('[a-z][0-9][a-z]', msg)#  匹配整个字符串,一直到结尾
print(result)#['d7v', 'd8h']
输出:
['23', '34']
None
<re.Match object; span=(2, 4), match='23'>
d7v
['d7v', 'd8h']

注意:
findall方法匹配时,如果匹配规则里有分组,则只匹配分组数据

ret = re.findall(r'\w+@(qq|126|163)\.com', '123@qq.com;aa@163.com;bb@126.com')
print(ret)#['qq', '163', '126']

如果正则表达式里存在多个分组,则会把多个分组匹配成元组

ret = re.findall(r'\w+@(qq|126|163)(\.com)', '123@qq.com;aa@163.com;bb@126.com')
print(ret)#[('qq', '.com'), ('163', '.com'), ('126', '.com')]

如果想要让findall匹配所有的内容,而不仅仅只是匹配正则表达式里的分组,可以使用 ?:来将分组标记为非捕获分组。

ret = re.findall(r'\w+@(?:qq|126|163)(\.com)', '123@qq.com;aa@163.com;bb@126.com')
print(ret)#['.com', '.com', '.com']

ret = re.findall(r'\w+@(?:qq|126|163)\.com', '123@qq.com;aa@163.com;bb@126.com')
print(ret)#['123@qq.com', 'aa@163.com', 'bb@126.com']

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

和 findall 类似,在字符串中找到正则表达式所匹配的所有子串,并把它们作为一个迭代器返回。

ret = re.finditer(r'\d+', 'he123456')# 得到的结果是一个可迭代对象
for x in ret:# 遍历 ret 取出里面的每一项匹配
    print(x.group(), x.span())#123456 (2, 8)# 匹配对象里的group保存了匹配的结果

ret = re.finditer(r'\d', 'he123456')
for x in ret:
    print(x.group(), x.span())
输出:
123456 (2, 8)
1 (2, 3)
2 (3, 4)
3 (4, 5)
4 (5, 6)
5 (6, 7)
6 (7, 8)

re.sub(pattern, repl, string, count, flags)

result = re.sub(r'\d+', '90', 'java:99,python:100')
print(result)#java:90,python:90
def func(temp):
    num = temp.group()
    num1 = int(num) + 1
    return str(num1)

result = re.sub(r'\d+', func, 'java:99,python:100')
print(result)#java:100,python:101

re.split(pattern, string, maxsplit, flags)

将分割的内容保存到列表中

result = re.split(r'[,:]', 'java:99,python:100')
print(result)#['java', '99', 'python', '100']

三re.Match类

相关属性:
pos 搜索的开始位置
endpos 搜索的结束位置
string 搜索的字符串
re 当前使用的正则表达式的对象
lastindex 最后匹配的组索引
lastgroup 最后匹配的组名
group(index=0) 某个分组的匹配结果。如果index等于0,便是匹配整个正则表达式
groups() 所有分组的匹配结果,每个分组的结果组成一个列表返回
groupdict() 返回组名作为key,每个分组的匹配结果座位value的字典
start([group]) 获取组的开始位置
end([group]) 获取组的结束位置
span([group]) 获取组的开始和结束位置
expand(template) 使用组的匹配结果来替换模板template中的内容,并把替换后的字符串返回

ret = re.search('(abc)+', 'xxxabcabcabcdef')
print(ret.pos) # 搜索开始的位置,默认是0
print(ret.endpos)# 搜索结束的位置,默认是字符串的长度
print(ret.group(0))# abcabcabc 匹配整个表达式
print(ret.group(1))# abc 第一次匹配到的结果
print(ret.span())#(3, 12) 开始和结束位置
print(ret.groups())# 表示当正则表达式里有多个分组时,多个分组的匹配结果
输出:
0
15
abcabcabc
abc
(3, 12)
('abc',)

四re.compile方法的使用

我们在使用正则表达式时,可以直接调用re 模块的 match,search,findall等方法,传入指定的正则表达式。同时,也可以调用re.compile方法,生成一个正则表达式对象,再调用这个正则表达式对象的相关方法实现匹配

msg = '娜扎热巴黛丝佟丽娅'

pattern = re.compile('佟丽娅')
result = pattern.search(msg)
print(result)
输出:
<re.Match object; span=(6, 9), match='佟丽娅'>

五 正则表达式的字符和特殊字符

\b 匹配一个单词边界也就是指单词和空格间的位置

msg = 'aa*py ab.txt bb.py kk.png uu.py apyb.txt'
result = re.findall(r'\w+\.py\b', msg)#  .前面的\表示转义
print(result)#['bb.py', 'uu.py']

\B 非单词边界

\d 匹配数字,0~9之间任意的数字,等同于[0 ~9]

print(re.search('he\dllo', 'he8llo'))#<re.Match object; span=(0, 6), match='he8llo'>
print(re.search('he[0-9]llo', 'he9llo'))#<re.Match object; span=(0, 6), match='he9llo'>
print(re.search('he\dllo', 'heallo'))#None

\D 匹配非数字字符,可以理解为对\d取反 等同于[^ 0 – 9 ]

print(re.search('hello\D', 'hello1'))#None
print(re.search('hello\D', 'hello_'))#<re.Match object; span=(0, 6), match='hello_'>
print(re.search('hello\D', 'helloS'))#<re.Match object; span=(0, 6), match='helloS'>

\w 匹配数字,字母,下划线 等同于 [0-9a-zA-Z_ ]

print(re.search('hello\w', 'hello!'))#None
print(re.search('hello\w', 'hello9'))#<re.Match object; span=(0, 6), match='hello9'>
print(re.search('hello\w', 'hellowe'))#<re.Match object; span=(0, 6), match='hellow'>   只匹配一个
print(re.search('hello\w', 'helloD'))#<re.Match object; span=(0, 6), match='helloD'>
print(re.search('hello\w', 'hello_'))#<re.Match object; span=(0, 6), match='hello_'>

\W 匹配非数字,字母,下划线 等同于 [^0-9a-zA-Z_ ]

print(re.search('hello\W', 'hello!'))#<re.Match object; span=(0, 6), match='hello!'>
print(re.search('hell\W', 'hello9'))#None


\s 匹配任意的空白字符 (空格,回车,换行,制表符,换页)等同于[ \r \n \t \f]
\S 匹配任意的非空白字符 (空格,回车,换行,制表符,换页)等同于[ ^ \r \n \t \f]

#\t  是空格
print(re.search('he\sllo', 'he\tllo'))#<re.Match object; span=(0, 6), match='he\tllo'>
print(re.search('he\Sllo', 'he\tllo'))#None

^ 开头
–表示一个区间
. 表示匹配除了换行符之外的任意字符
$ 表示匹配到结尾
* 用于将前面模式匹配0次或者多次(贪婪模式,即尽可能多的匹配)》=0
+ 用于将前面的模式匹配1次或多次(贪婪模式)>=1
? 用于将前面的模式匹配0次或1次(贪婪模式)0,1
{m} 用于验证将前面的模式匹配m次
{m,} 用于验证将前面的模式匹配m次或多次 >=m
{m,n} 用于验证将前面的模式匹配大于等于m次且小于等于n次
(word|word|word) 表示或者 | 表示或者
[abc]表示一个字母而不是一个单词
[ ] 表示范围,用于表示一组字符,如果^ 是第一个字符,则表示的是一个补集。比如 [0-9]表示所有数字 [^ 0-9]表示除了数字外的字符
*? +? ??是 * + ?的非贪婪模式(尽可能少的匹配)

六 正则表达式的模式修饰符

用来修饰正则表达式,是一个可选参数
re.S 可以使正则表达式中的 ’ . ’ 匹配到换行符

import re
print(re.search('shenzhen.', 'shenzhen9'))#<re.Match object; span=(0, 9), match='shenzhen9'>
print(re.search('shenzhen.', 'shenzhen\n'))#None
print(re.search('shenzhen.', 'shenzhen\n', re.S))#<re.Match object; span=(0, 9), match='shenzhen\n'>

re.I 表示正则表达式在匹配后面的内容时忽略大小写。

print(re.search('shenzhen[a-z]', 'shenzhenM'))#None
print(re.search('shenzhen[a-z]', 'shenzhenM', re.I))#<re.Match object; span=(0, 9), match='shenzhenM'>

re.M 多行匹配,影响 ^ 和 $ ,每个换行都认为是一个结尾
\w+$ 表示匹配以一个或者多个字母结尾

print(re.findall(r'\w+$', 'i am boy\n you are girl\n he is man\n', re.M))#['boy', 'girl', 'man']
print(re.findall(r'\w+$', 'i am boy\n you are girl\n he is man\n'))#['man']

七 正则表达式贪婪与非贪婪

python里的数量词默认是贪婪的,总是尝试匹配尽可能多的字符
在非贪婪里则相反,总是尝试匹配尽可能少的字符
在“ * ” “ ?” “+” “{m,n}”后面加上?,是贪婪变成非贪婪

#贪婪模式
msg = 'abc123abc'
result = re.match(r'abc(\d+)', msg)
print(result)#输出:<re.Match object; span=(0, 6), match='abc123'>
#非贪婪模式
msg1 = 'abc123abc'
result = re.match(r'abc(\d+?)', msg1)
print(result)#输出:<re.Match object; span=(0, 4), match='abc1'>

版权声明:本文为weixin_62623950原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。