Python 笔记 — 正则基础

一、介绍

1、概述

正则表达式是一个特殊的字符序列,它能帮助你方便的检查一个字符串是否与某种模式匹配

正则表达式是一个很强大的字符串处理工具,几乎任何关于字符串的操作都可以使用正则表达式来完成。

在 Python 中需要通过正则表达式对字符串进行匹配的时候,可以使用 re 模块

2、应用场景

表单验证(例如 : 手机号、邮箱、身份证… )

爬虫

处理文本和数据

3、格式

# 导入 re 模块
import re

# 使用 match 方法进行匹配操作 re.match() 能够匹配出以 xxx 开头的字符串
# 如果起始位置没有匹配成功,返回 None
result = re.match(正则表达式,要匹配的字符串)
# 如果上一步匹配到数据的话,可以使用 group 方法来提取数据
result.group()

4、案例

import re
result = re.match('it', 'itsixstar.cn')
print(result.group())  # it

二、匹配单个字符

字符功能
.匹配任意1个字符(除了\n)
[ ]匹配[ ]中列举的字符
\d匹配数字,即0-9
\D匹配非数字,即不是数字
\s匹配空白,即空格,tab键
\S匹配非空白
\w匹配单词字符,即a-z、A-Z、0-9、_
\W匹配非单词字符
import re

# . 匹配任意1个字符(除了\n)
ret = re.match(".","M")
print(ret.group())  # M

ret = re.match("t.o","too")
print(ret.group())  # too

ret = re.match("t.o","two")
print(ret.group())  # two

# [] 匹配[ ]中列举的字符
# 如果 hello 的首字符小写,那么正则表达式需要小写的 h
ret = re.match("h","hello Python")
print(ret.group())  # h

# 如果 hello 的首字符大写,那么正则表达式需要大写的 H
ret = re.match("H","Hello Python")
print(ret.group())  # H

# 大小写h都可以的情况
ret = re.match("[hH]","hello Python")
print(ret.group())  # h
ret = re.match("[hH]","Hello Python")
print(ret.group())  # H
ret = re.match("[hH]ello Python","Hello Python")
print(ret.group())  # Hello Python

# 匹配0到9第一种写法
ret = re.match("[0123456789]Hello Python","7Hello Python")
print(ret.group())  # 7Hello Python

# 匹配0到9第二种写法
ret = re.match("[0-9]Hello Python","7Hello Python")
print(ret.group())  # 7Hello Python

ret = re.match("[0-35-9]Hello Python","7Hello Python")
print(ret.group())  # 7Hello Python

# 下面这个正则不能够匹配到数字4,因此 ret 为 None
ret = re.match("[0-35-9]Hello Python","4Hello Python")
# print(ret.group())  # AttributeError: 'NoneType' object has no attribute 'group'

# 普通的匹配方式 \d 匹配数字,即0-9
ret = re.match("嫦娥1号","嫦娥1号发射成功")
print(ret.group())  # 嫦娥1号

# 使用\d进行匹配
ret = re.match("嫦娥\d号","嫦娥1号发射成功")
print(ret.group())  # 嫦娥1号

# \w匹配单词字符,即a-z、A-Z、0-9、_
res = re.match('\w', '4sixstar')
print(res.group())  # 4

三、匹配多个字符

字符功能
*匹配前一个字符出现0次或者无限次,即可有可无
+匹配前一个字符出现1次或者无限次,即至少有1次
?匹配前一个字符出现1次或者0次,即要么有1次,要么没有
{m}匹配前一个字符出现m次
{m,n}匹配前一个字符出现从m到n次
import re

# * 匹配出,一个字符串第一个字母为大小字符,后面都是小写字母并且这些小写字母可有可无
ret = re.match("[A-Z][a-z]*","M")
print(ret.group())  # M

res = re.match('[A-Z]*[a-z]', 'SSixstar')
print(res.group())  # SSi

ret = re.match("[A-Z][a-z]*","Aabcdef")
print(ret.group())  # Aabcdef

# +:匹配出,变量名是否有效
ns = ['jiuge', '2jiuge', 'jg', '_jiuge']
for i in ns:
    res = re.match('[ a-zA-Z_]+[\w]*', i)
    if res:
        print('正确的名字:', res.group())
    else:
        print("名字 %s 非法" % i)

# 运行结果:
# 正确的名字: jiuge
# 名字 2jiuge 非法
# 正确的名字: jg
# 正确的名字: _jiuge

# ? 匹配数字 匹配前一个字符出现1次或者0次,即要么有1次,要么没有
res = re.match('[1-9]?[0-9]', '6946')
print(res.group())  # 69

res = re.match('[1-9]?', '6946')
print(res.group())  # 6

res = re.match('[1-9]?\d', '78')
print(res.group())  # 78

res = re.match('[1-9]?\d', '078')
print(res.group())  # 0

# {m} 匹配前一个字符出现m次, 8到20位的密码,可以是大小写英文字母、数字、下划线
ret = re.match("[a-zA-Z0-9_]{6}","12a3g45678")
print(ret.group())  # 12a3g4

res = re.match('[a-z0-9]{4}', 'abc234dss')
print(res.group())  # abc2

ret = re.match("[a-zA-Z0-9_]{8,20}","1ad12f23s34455ff66")
print(ret.group())  # 1ad12f23s34455ff66

ret = re.match("[a-zA-Z0-9_]{3,8}", "abc")
print(ret.group())  # abc

四、匹配开头结尾

字符功能
^匹配字符串开头
$匹配字符串结尾
import re

res = re.match('^ab', 'absdf')  # 由'ab'开头就匹配成功
print(res.group())  # ab

res = re.match('^[0-9]', '23absdf')  # ^[0-9]表示由0-9之间开头就成功
print(res.group())  # 2

res = re.match('[^0-9]', 'absdf')  # [^0-9] 表示匹配所有的非数字字符
print(res.group())  # a

总结:

'abc' 表示字符串中有’abc’就匹配成功 。

'[abc]' 表示字符串中有’a’或’b’或’c’就匹配成功 。

'^abc' 表示字符串由’abc’开头就匹配成功 。

'^[abc]' 表示字符串由’a’或’b’或’c’开头就匹配成功 。

'[^abc]' 表示匹配’a’,‘b’,‘c’之外的字符。如果一个字符串是由’a’,‘b’,'c’组合起来的,那就是假。

import re

elist = ['jiuge@qq.com', 'jiu@qq.compu', 'com.jiuge@qq.com', 'jiuge@163.com']
for i in elist:
    # res = re.match('[\w]*@qq.com$', i)
    res = re.match('[\w]{4,20}@qq.com$', i)
    if res:
        print('%s 符合要求' % res.group())
    else:
        print('%s 不符合要求' % i)

# 运行结果:
# jiuge@qq.com 符合要求
# jiu@qq.compu 不符合要求
# com.jiuge@qq.com 不符合要求
# jiuge@163.com 不符合要求

五、匹配分组

字符功能
|匹配左右任意一个表达式
(ab)将括号中字符作为一个分组
\num引用分组 num 匹配到的字符串
(?P)分组起别名
(?P=name)引用别名为 name 分组匹配到的字符串
import re

# | 匹配左右任意一个表达式
res = re.match('[1-9]?\d$', '10')
print(res.group())  # 10

res = re.match('[1-9]?\d$', '100')
# print(res.group())  # 报错

res = re.match('[1-9]?\d$|100', '100')
print(res.group())  # 100

# () 将括号中字符作为一个分组
res = re.match('\w{4,20}@163.com', 'test@163.com')
print(res.group())  # test@163.com

res = re.match('\w{4,20}@(163|qq|129).com', 'test@qq.com')
print(res.group())  # test@qq.com
import re

res = re.match("<[a-zA-Z]*>", "<html>hh</html>")
print(res.group())  # <html>

res = re.match("<[a-zA-Z]*>\w*", "<html>hh</html>")
print(res.group())  # <html>hh

res = re.match("<[a-zA-Z]*>\w*</[a-zA-Z]*>", "<html>hh</html>")
print(res.group())  # <html>hh</html>

ret = re.match(r"<(\w*)>\w*</\1>", "<html>hh</html>")
print(ret.group())  # <html>hh</html>
import re

ret = re.match(r"<(\w*)>\w*</\1>", "<html>hh</htmlre>")
# 因为2对<>中的数据不一致,所以没有匹配出来,前后不匹配,出现错误。
# print(ret.group())  # 报错:AttributeError: 'NoneType' object has no attribute 'group'

# \number
ret = re.match(r"<(\w*)><(\w*)>.*</\2></\1>", "<html><h1>hh</h1></html>")
print(ret.group())  # <html><h1>hh</h1></html>

ret = re.match(r"<(\w*)><(\w*)>.*</\2></\1>", "<html><h2>hh</h1></html>")
# print(ret.group())  # 报错:AttributeError: 'NoneType' object has no attribute 'group'

# (?P<name>) 分组起别名
ret = re.match(r"<(?P<n1>\w*)><(?P<n2>\w*)>.*</(?P=n2)></(?P=n1)>", "<html><h1>www.baidu.com</h1></html>")
print(ret.group())  # <html><h1>www.baidu.com</h1></html>

六、高级用法

1、search 函数

search() 会扫描整个字符串并返回第一个成功的匹配。

import re

res = re.search('\d+', '阅读次数为23次')
print(res.group())  # 23

search 函数和 match 函数有点类似,都可以匹配模式。

match 和 search 的区别:

match 函数只能够字符串的开始位置开始匹配,而 search 扫描整个 string 查找匹配,可以匹配字符串的任意位置,但也是返回找到的第一个匹配的模式。

import re

res = re.match('ab', '12abwe')
# print(res.group())  # 错误:AttributeError: 'NoneType' object has no attribute 'group'

res2 = re.search('ab', '12abwe')
print(res2.group())  # ab

2、findall

findall()列表形式返回匹配到的字符串。

在字符串中找到正则表达式所匹配的所有子串,并返回一个列表,如果没有找到匹配的,则返回空列表。

match 和 search 是匹配一次,findall 匹配所有。

import re

res = re.findall('\d', 'a=1,b=2,c=3')
print(res)  # ['1', '2', '3']

总结:

match:从头开始匹配,返回 object,匹配一次,最不常用。

search:仅返回第一个匹配,返回object,匹配一次,较常用 。

findall:匹配所有字符串,返回列表,匹配所有,最常用。

3、sub

sub() 将匹配到的数据进行替换

re.sub(pattern, repl, string, count = 8, flags = 0)

其中必须的三个参数:pattern, repl, string

两个可选参数: count, flags

count 指定要替换的个数

import re

res = re.search('\d+', '20')
print(res.group())  # 20

res2 = re.sub('\d', '20', '我读了2页')
print(res2)  # 我读了20页
import re

str1 = '''
<div>
<p>岗位职责:</p>
<p>完成推荐算法、数据统计、接口、后台等服务器端相关工作</p>
<p><br></p>
<p>必备要求:</p>
<p>良好的自我驱动力和职业素养,工作积极主动、结果导向</p>
<p>&nbsp;<br></p>
<p>技术要求:</p>
<p>1、一年以上 Python 开发经验,掌握面向对象分析和设计,了解设计模式</p>
<p>2、掌握HTTP协议,熟悉MVC、MVVM等概念以及相关WEB开发框架</p>
<p>3、掌握关系数据库开发设计,掌握 SQL,熟练使用 MySQL/PostgreSQL 中的一种<br></p>
<p>4、掌握NoSQL、MQ,熟练使用对应技术解决方案</p>
<p>5、熟悉 Javascript/CSS/HTML5,JQuery、React、Vue.js</p>
<p>&nbsp;<br></p>
<p>加分项:</p>
<p>大数据,数理统计,机器学习,sklearn,高性能,大并发。</p>
</div>
'''
b = re.sub(r'<[^>]*>|&nbsp;|\n', "", str1)
print(b)

# 运行结果:
# 岗位职责:完成推荐算法、数据统计、接口、后台等服务器端相关工作必备要求:良好的自我驱动力和职业素养,工作积极主动、结果导向技术要求:1、一年以上 Python 开发经验,掌握面向对象分析和设计,了解设计模式2、掌握HTTP协议,熟悉MVC、MVVM等概念以及相关WEB开发框架3、掌握关系数据库开发设计,掌握 SQL,熟练使用 MySQL/PostgreSQL 中的一种4、掌握NoSQL、MQ,熟练使用对应技术解决方案5、熟悉 Javascript/CSS/HTML5,JQuery、React、Vue.js加分项:大数据,数理统计,机器学习,sklearn,高性能,大并发。

4、split

split() 根据匹配进行切割字符串,并返回一个列表

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

pattern compile 生成的正则表达式对象,或者自定义也可。

string 要匹配的字符串。

maxsplit 指定最大分割次数,不指定将全部分割。

import re

res = re.split(';| ', 'a b;c 23')
print(res)  # ['a', 'b', 'c', '23']

七、贪婪和非贪婪

正则在进行匹配时,从开始位置查找最远的结束位置,这种模式称之为贪婪模式

在进行 HTML 标签类似内容获取时,贪婪模式会导致整个内容的返回,需要使用非贪婪模式

贪婪匹配:在满足匹配时,匹配尽可能长的字符串,默认情况下,采用贪婪匹配。

非贪婪匹配:在满足匹配时,匹配尽可能短的字符串,使用 ? 来表示非贪婪匹配。

固定的书写规则 :

.*? 这种方式就是非贪婪模式,或者说是惰性模式。

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

在"*“,”?“,”+“,”{m,n}"后面加上?,使贪婪变成非贪婪。

import re

res = re.match('ab*', 'abbbc')
print(res.group())  # abbb

res2 = re.search('ab*?', 'abbbc')
print(res2.group())  # a

res = re.match('a*', 'aaa')
print(res.group())  # aaa

res2 = re.match('a*?', 'aaa')
res2 = re.match('a+?', 'aaa')  # a
print(res2.group())  # 空字符串
import re

str3 = '<h1> hello world </h1>'
res = re.findall(r'<.*>', str3) # 贪婪模式
res2 = re.findall(r'<.*?>', str3) # 非贪婪模式

# 默认匹配到所有内容
print(res)  # ['<h1> hello world </h1>']
# 只想匹配两个标签的内容
print(res2)  # ['<h1>', '</h1>']
import re

st = 'ab1234ba'
res = re.match('ab(\d+)', st)
res2 = re.match('ab(\d+?)', st)
res3 = re.match('ab(\d+)ba', st)
res4 = re.match('ab(\d+?)ba', st)

print(res.group())  # ab1234
print(res2.group())  # ab1
print(res3.group())  # ab1234ba
print(res4.group())  # ab1234ba

八、原生字符串

1、Python 中字符串前面加上 r 表示原生字符串。

2、python 转义字符

\b 退格(Backspace)

\e 转义

\n 换行

\t 横向制表符

\' 单引号

print('abc\n123')
print('abc\\n123')

# 运行结果:
# abc
# 123
# abc\n123

3、假如你需要匹配文本中的字符 \,那么使用编程语言表示的正则表达式里将需要4个反斜杠\\\\

前两个和后两个分别用于在编程语言里转义成反斜杠,转换成两个反斜杠后再在正则表达式里转义成一个反斜杠。

因为在正则表达式中,\\ 就是一个反斜杠。

import re

res = re.match('\\\\', '\def')
print(res.group())  # \

4、正则表达式可以使用 r'\\'表示。

import re

res = re.match(r'\\', '\def')
print(res.group())  # \
    
m = 'c:\\a\\b\\d'
print(m)  # c:\a\b\d

res = re.match('c:\\\\', m)
print(res.group())  # c:\

res2 = re.match(r'c:\\a', m)
print(res2.group())  # c:\a

记录学习过程,欢迎讨论交流,尊重原创,转载请注明出处~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值