Python(19)正则表达式

一、正则表达式简介

1、正则表达式的定义
正则表达式是对字符串操作的一种逻辑公式,就是用事先定义好的一些特定字符及这些特定字符的组合,组成一个“规则字符串”,这个“规则字符串”用来表达对字符串的一种过滤逻辑。

正则表达式是对字符串(包括普通字符(例如,a 到 z之间的字母)和特殊字符(称为“元字符”))操作的一种逻辑公式,就是用事先定义好的一些特定字符、及这些特定字符及这些字符的组合,组成一个“规则字符串”,这个“规则字符串”用来表达对字符串的一种过滤逻辑。
正则表达式是一种文本模式,该模式描述在搜索文本时要匹配的一个或多个字符串。

正则表达式,又称正规表达式、正规表示法、正规表达式、规则表达式、常规表达法(英语:Regular Expression,在代码中常简写为regex、regexp或RE),是计算机科学的一个概念。
正则表达式使用单个字符来描述、匹配一系列某个句法规则的字符串。很多文本编辑器里,正则表达式通常被用来检索、替换那些匹配某个模式的文本。
Regular Expression的“Regular”一般被译为“正则”、“正规”、“常规”。此处的“Regular”即是“规则”、“规律”的意思,Regular Exception即“描述某种规则的表达式”之意。
正则在所有语言中都有的内容。

2、正则表达式的作用和特点
给定一个正则表达式和另一个字符串,我们可以达到如下的目的:
1)、给定的字符串是否符合正则表达式的过滤逻辑(称作“匹配”);
2)、可以通过正则表达式,从字符串中获取我们想要的特定部分。

正则表达式的特点是:
1)、灵活性、逻辑性和功能性非常强;
2)、可以迅速地用极简单的方式达到字符串的复杂控制。
3)、对于刚接触的人来说,比较晦涩难懂。

场景:
如何判断一个字符串是手机号呢?
判断邮箱为163或者126的所有邮箱地址?

加入你在写一个爬虫,你得到了一个网页的HTML源码,其中有一段
<html><body><h1>hello world</h1></body></html>
你想要把这个hello world提取出来,但你这是如果只会python的字符串处理,那么第一反应可能是
s = "<html><body><h1>hello world</h1></body></html>"
start_index = s.find('<h1>)

 

二、Python  re模块    regex正则模块

import re    导入正则模块

\A:表示从字符串的开始处匹配
\Z:表示从字符串的结束处匹配,如果存在换行,只匹配到换行前的结束字符串。
\b:匹配一个单词边界,也就是指单词和空格间的位置。例如,'py\b' 可以匹配“python”中的'py',但不能匹配“openyxl”中的py
\B:匹配非单词边界。'py\b' 可以匹配"openyxl"中的'py',但不能匹配“python”中的'py'
\d:匹配任意数字,等价于[0-9]。     digit
\D:匹配任意非数字字符,等价于[^\d]。      not digit
\s:匹配任意空白字符,等价于[\t\n\r\f]。      space
\S:匹配任意非空白字符,等价于[^\s]。      not space
\w:匹配任意字母数字及下划线,等价于[a-zA-Z0-9_]。
\W:匹配任意非字母数字及下划线,等价于[^\w]。
\\:匹配原义的反斜杠\。

'.' 用于匹配除换行符(\n)之外的所有字符。
'^' 用于匹配字符串的开始,即行首。
'$' 用于匹配字符串的末尾(末尾如果有换行符\n,就匹配\n前面的那个字符),即行尾。

定义正则验证次数
'*' 用于将前面的模式匹配0次或多次(贪婪模式,即尽可能多的匹配)  >= 0次
'+' 用于将前面的模式匹配1次或多次(贪婪模式)   >= 1次
'?' 用于将前面的模式匹配0次或1次(贪婪模式)   0或1次
'{m}' 用于验证将前面的模式匹配m次
'{m,}' 用于验证将前面的模式匹配m次或多次    >= m次
'{m,n}' 用于验证将前面的模式匹配大于等于m次并且小于等于n次    >= m次
'*?, +?. ??'  即上面三种特殊字符的非贪婪模式(尽可能少的匹配)
'{m, n}' 用于将前面的模式匹配m次到n次(贪婪模式),即最小匹配m次,最大匹配n次
'{m, n}?' 即上面'{m,n}'的非贪婪版本

'\\': '\'是转义字符,在特殊字符前面加上\,特殊字符就失去了其所代表的含义,比如\+就仅仅代表加号+本身
'[]' 用于标示一组字符,如果^是第一个字符,则标示的是一个补集。比如[0-9]表示所有的数字,[^0-9]表示除了数字外的字符
'|' 比如A|B用于匹配A或B
'(...)' 用于匹配括号中的模式,可以在字符串中检索或匹配我们所需要的内容
import re

#正则表达式  输入内容合法性验证

msg = 'this is message'
#匹配
pattern = re.compile('this')
#拿到正则,match匹配msg  ,没有匹配则返回None    match只能从头匹配
result = pattern.match(msg)
print(result)

#使用正则re模块方法:match
# re.match(正则表达式, 字符串)    match从开头进行匹配,开头不匹配则返回None
result = re.match('is', msg)
print(result)

# re.search(正则表达式, 字符串)     进行正则字符串匹配方法,匹配的是整个字符串
result = re.search('is', msg)   #<re.Match object; span=(2, 4), match='is'>   span匹配的位置(左包含,有不包含)  match匹配的内容
print(result)
print(result.span())    #返回位置
print(result.group())   #使用group提取到匹配的内容


#正则的符号
s = '哈哈哈2a'
result = re.search('[0-9][a-z]', s)
print(result)

# a2b h6k
msg = 'abcd7vjkfd8hdf00'
#[] 表示的是一个范围    re.search  只有有匹配的后面就不会继续进行检索,找到一个匹配的就会停止
result = re.search('[a-z][0-9][a-z]', msg)
print(result.group())

#re.findall  匹配整个字符串,找到一个一直会继续找,一直找到字符串结尾
result = re.findall('[a-z][0-9][a-z]', msg) #['d7v', 'd8h']
print(result)

#a7a  a88a  a7878a
msg = 'a7opa88akjgka898a788a'
# + >= 1
result = re.findall('[a-z][0-9]+[a-z]', msg)    #['a7o', 'a88a', 'a898a']
print(result)

#QQ验证  1、验证长度大于5  2、首位不是0
qq = '14944689962'
# ^开头  $结尾
result = re.match('^[1-9][0-9]{4,10}$', qq)
print(result)

#用户名可以是字母或者数字,不能是数字开头,用户名长度必须6位以上[0-9a-zA-Z]
username = 'admin001**'
result = re.search('^[a-zA-Z]\w{5,}$', username)
print(result)

msg = 'aa*py ab.txt bb.py kk.png uu.py apyb.tst'
# 字符串中\b    正则将\b写为'\\b'或r'\b',防止出现转义
# . 匹配除\n之外任意字符
result = re.findall(r'\w+\.py\b', msg)
print(result)

基本正则使用总结: 

. 除\n外任意字符
^ 开头
$ 结尾
[] 范围 [abc] [a-z] [a-z*$%]  或者关系
正则预定义:
\s  空白(空格)
\b  边界
\d  数字
\w  word [0-9a-zA-Z_]
大写为反面 \S 非空格 \D非数字 ...

'\w[0-9]'  ---> \w [0-9] 只能匹配一个字母

量词:
*  >= 0
+  >= 1
?  0或1

手机号码正则
re.match('^1[35789]\d{9}$', phone_number)
{m}  固定m位
{m,}  >= m位
{m, n}  m位 <= phone_number <= n位

 

三、正则表达式的分组

分组
匹配数字0-100

|  或者
()  整体范围的或者     (word|word|word)
[]  单个字母的或者     [abc] 或者是字母a,或者是字母b,或者是字母c,表示的是一个字母而不是一个单词
import re

n = '100'
result = re.match(r'[1-9]?\d', n)    #<re.Match object; span=(0, 2), match='10'>
print(result)

#改进版
result = re.match(r'[1-9]?\d?$|100$', n)
print(result)

#验证输入的邮箱 163 126 qq
email = '73877884@163.com'
result = re.match(r'\w{5,20}@(163|126|qq)\.(com|cn)$', email)
print("email是否匹配-->", result)

#不能以4、7结尾的手机号码(11位)
phone = '15901018867'
result = re.match(r'1[35789]\d{8}[0-35-689]$', phone)
print(result)

#爬虫
phone = '010-12345678'
result = re.match(r'(\d{3}|\d{4})-(\d{8})$', phone)
print(result)
#分别提取
print(result.group())       #010-12345678
#() 表示分组  group(1)表示提取到第一组的内容  group(2)表示第二组的内容
print(result.group(1))      #010
print(result.group(2))      #12345678

#提取h5标签中内容
msg = '<html>abc</html>'
msg1 = '<h1>hello</h1>'
result = re.match(r'<\w+>(.+)</\w+>$', msg1)
print(result)
print(result.group(1))

#分组引用数字匹配  number
msg2 = '<h1>hello</h2>'
#匹配标签正好成对    \1为引用第一组内容
result = re.match(r'<(\w+)>(.+)</\1>$', msg2)
print(result)

msg3 = '<html><h1>hello world</h1></html>'
result = re.match(r'<(\w+)><(\w+)>(.+)</\2></\1>$', msg3)
print(result)
print(result.group(1))
print(result.group(2))
print(result.group(3))


#起名的方式  (?P<名字>正则) (?P=名字)    分组起名
msg4 = '<html><h1>abc</h1></html>'
result = re.match(r'<(?P<name1>\w+)><(?P<name2>\w+)>(.+)</(?P=name2)></(?P=name1)>', msg4)
print(result)
print(result.group(1))
print(result.group(2))
print(result.group(3))

分组总结:

分组: () --->  result.group(1) 获取组中匹配的内容

在分组的时候还可以结合 |或者 使用
    result = re.match(r'(\d{3}|\d{4})-(\d{8})$', phone)
    print(result)
    
不需要引用分组的内容:
    result = re.match(r'<\w+>(.+)</\w+>$', msg1)
    print(result)
    print(result.group(1))
    
引用分组匹配的内容:
1、number    \number 引用第number组的数据
    (\w+)(\d*) ---> group(1) group(2)
    引用:
    (\w+)(\d*)    \1  \2  表示引用前面的内容

    result = re.match(r'<(\w+)><(\w+)>(.+)</\2></\1>$', msg3)
    print(result)

2、?P<名字>  起名
    (?P<name>\w+)  
    引用:(?P=name)

    result = re.match(r'<(?P<name1>\w+)><(?P<name2>\w+)>(.+)</(?P=name2)></(?P=name1)>', msg4)
    print(result)
    
re模块使用函数:
match   从开头进行匹配
search  只匹配一次
findall 查找所有

sub  将匹配的数据进行替换
re.sub(正则表达式, 替换的新内容(可以是内容,也可以是函数), 正则匹配的内容)

split
re.split(正则表达式, 正则匹配的内容)    将分割的内容都保存到列表中

 

四、正则 re 模块函数

match(pattern, str)     从开头进行匹配

search(pattern, str)     只匹配一次

findall(pattern, str)    查找所有

 

sub 将匹配的数据进行替换

re.sub(正则表达式, 替换的新内容(可以是内容,也可以是函数), 正则匹配的内容)

 

split   分割

re.split(正则表达式, 正则匹配的内容) 将分割的内容都保存到列表中

import re

def func(temp):
    num = temp.group()
    num1 = int(num) + 1
    return str(num1)

#替换的是内容
result = re.sub(r'\d+', '1000', 'java:99, python:100')
print(result)   #java:1000, python:1000

#替换的是函数
result = re.sub(r'\d+', func, 'java:99, python:100')
print(result)

#既可以按照, 逗号 也可以按照:冒号 进行切割
result = re.split(r'[,:]', 'java:99, python:100')
print(result)

 

五、正则  贪婪与非贪婪

Python 里数量词默认是贪婪的(在少数语言里也可能是默认非贪婪),总是尝试匹配尽可能多的字符;

非贪婪则相反,总是尝试匹配尽可能少的字符

在"*", "?", "+", "{m,n}"后面加上?,则贪婪变成非贪婪
import re

msg5 = 'abc123abc'
#默认是贪婪的
result = re.match(r'abc(\d+)', msg5)
print(result)            #<re.Match object; span=(0, 6), match='abc123'>
print(result.group())    #abc123

#如果想将贪婪模式变成非贪婪模式
result = re.match(r'abc(\d+?)', msg5)
print(result)            #<re.Match object; span=(0, 4), match='abc1'>
print(result.group())    #abc1

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值