所有的模块要经历的两个步骤:
要操作的概念本身: 正则表达式 时间 等
使用模块去操作它: re time
re 模块
正则表达式
基础知识
什么是正则表达式?
一种匹配字符串的规则
正则表达式能做什么?
可以定制一个规则:
1. 来确认某一个字符串是否复合规则
2. 从大段字符串中找到复合规则的内容
程序领域:
1. 登录注册页的表单验证
如 手机号的格式判断
2 爬虫
把网页下载下来, 从里边提取一些信息, 找到我要的所有信息, 做数据分析
3. 自动化开发 日志分析
明确一件事:
正则表达式 是一种独立的语法
和python没有关系
正则表达式 元字符+量词
元字符
字符组 [ ] [ ^ ] 个性化定制,
下面这一组无法描述的一般用上面的字符组的形式
[ ] 在一个字符位置上能出现的内容 , 之约束一个位置
[\d\s]一个特殊元字符无法描述一个字符出现的内容了
e.g 这个范围是根据 ASCII码中的大小顺序来说的
[ 1bc ] 表示这个位置上 1, b, c 都可以放
[ 0-9 ] 表示 这个位置上 可以是 1 到 9 的任意数字
不能是 9-0 因为 范围只能是 从小到大
[ a-z ] 表示这个位置上 只能是 小写 的 26 个英文字母
不能是 z-a 范围也只能是 从小到大
[ A-Z ] 表示这个位置上 只能是 大写的 26 个英文字母
不能是 Z到a A 范围也只能是 从小到大
[ 0-9 ] [ a-z ] [ A-Z ] 这样表示 约束的是三个字符
顺序必须是 数字 小写字母 大写字母
[ 0-9 a-z A-Z ] 表示一个字符 上 数字字母都可以
[ ^ ] 表示非 ^后边的字符 这个格式可以放到任何位置
e.g
[ ^ abc ] 表示这个字符上 非 a 非b 非c
| ()
| 表示 或者 左边或者右边
( ) 表示分组 可以对括号中的一组进行 统一的量词的使用
\w \d \s( \n \t ) \W \D \S
\w == [0-9a-zA-Z_] 表示匹配 数字字母下划线 都可以
\d == [0-9] 表示 匹配一个数字
\s ==[ \n \t ] 表示 任意空白符 包括 空格 回车 制表符 tab
\n 表示只匹配 回车换行
\t 表示 之匹配 制表符
\W 表示 匹配 非数字字符下划线
\D 表示 匹配 非数字
\S 表示匹配 非空白
[\d\D] [\w\W] [\s\S] 都可以表示 匹配所有
^ $ .
^ 表示 以什么开头
$ 表示 以什么结尾
. 表示除了 \n 换行符外的任意字符 爬虫容易用 但是表单验证不容易用
量词
? + *
? 表示 重复 0 次 或 1 次
+ 表示 重复 1次 到 无穷多次
* 表示 重复 0次 到 无穷多次
{ n } { n , } { n , m }
{ n } 表示 重复 n 次
{ n , } 表示 至少重复n 次 贪婪匹配 尽可能多的去匹配 采用的是回溯算法
{ n , m } 表示重复 n 到 m 次
特殊的用法和现象
? 的使用
1. 在量词后边 跟一个? 表示 取消 贪婪匹配 非贪婪 找复合条件的但是最短的
?? *? +? { n }?
.*?x 最常用 表示 匹配任意字符直到找到一个x
在python中使用正则表达式
转义符:
\n 里边的 \ 转义符 赋予了这个n一个特殊的意义, 表示换行符
若想打印出来 \n 必须要在他前边 再加一个 \ 也就是说 \\n 才表示打印出来的 \n形式
因此 当你看到这个 \ 的时候不应该理解为 这是一个 \ , 它是一个转义符
你要是想把这个转义符变为一个字符串 \ , 它必须经过转义
而 \\ 就等于是 字符串数据类型的 \
如果一个字符串类型的\ 取消了 它转义符的意思 , 就表示 一个字符串
那么就不需要 再使用 \\ 来表示 \ 了
我们就在字符串前面 加上一个 r ' ' , 取消这个字符串中所有 \ 的转义
e.g import re
ret = re . search( '' \\\\n '' , '' \\n '' )
print(ret.group()) ===> \
ret = re . search( r'' \\n '' ,r '' \n '' ) # 前边加上r 就相当于取消了 转义 全是按照原来的 来匹配的
print(ret.group()) ===> \n
在测试工具中 , 如果带了 \ , 你有担心 他会出现转义的情况
不管三七二十一 , 在测试工具中 里测好了代码
拿到 python 中 , 统一 放在 字符串 r ' ' 引号中 就行了
re模块
常用的方法 相当于字符串的 匹配
import re
findall ***** 一般在 获取所有 匹配项的时候用 因为结果是 匹配项组成的一个 列表
语法 ret = re. findall( ' 正则表达式 ' , ' 要匹配的字符串 ' )
返回值 print( ret ) 是一个列表 其中的元素是 符合正则的 每一个结果 [ ' ' , ' ' , ' ' ]
若没符合正则的 结果 则返回值为 空列表 [ ]
返回值个数 : 只有一个 列表 或 空列表
e.g import re
ret = re.findall( ' \d+ ' , ' 1457jhuuh5866' )
print( ret ) ===> [ ' 1457 ' , ' 5866 ' ]
ret = re.findall( ' \d+ ' , ' jkugjhuuh' )
print( ret ) ===> [ ]
search ***** 一般在取 匹配项的 第一个 值的时候用
语法 ret = re . search( ' 正则表达式 ' , ' 要匹配的字符串 ' )
print( ret ) ===> <_sre.SRE_Match object; span=(0, 5), match='18575'>
print( type(ret) ) ===> <class '_sre.SRE_Match'>
print( ret.group() ) ===> 将符合正则的 第一项 拿出来
返回值 是符合正则结果的 对象
返回值个数 1
若没有符合正则的 项 则返回类型 为 None Type
因此 一般会这样写 if ret : print( ret.group() )
当符合正则的时候才打印 否则不打印 结果就为空 不会报错
e.g
ret = re.search( ' \d+ ' , ' 1457jhuuh5866' )
if ret : print( ret .group()) ===> 1457
ret = re.search( ' \d+ ' , ' jkugjhuuh' )
print( ret ) ===> NoneType
if ret : print( ret.group() ) ====> 啥都没有
match ** 不管正则表达式写成什么 都相当于 前边加了一个 ' ^ 正则 ' ,
就相当于 是判断 是否 以正则条件 开始的 无论是或否结果都是 一个返回值
语法 ret = re.match( ' 正则表达式 ' , ' 要匹配的字符串 ' )
print( ret ) ===> None 或者 <_sre.SRE_Match object; span=(0, 4), match='5856'>
返回值 print( ret.group() ) ===> 匹配对象 或 报错 NoneType
e.g ret = re.match( ' \d+ ' , ' 1457jhuuh5866' )
print( ret.group()) ====> 1457
ret = re.match( ' \d+ ' , ' jhuuh5866' )
print( ret.group()) ====> None
替换 *** 相当于 replace
sub *** 返回 一个 替换后的 结果 若没有替换则返回 原来的字符串
语法 ret =re.sub( ' 正则表达式 ' , ' 要替换的结果 ' , ' 要匹配的字符串' , 要替换的数量 )
返回值 print( ret ) ===> 替换的那个结果 若没换就是原来的 字符串
subn *** 返回 一个 元组形式 ( '' 结果 '' , 0 / 匹配的次数 )
语法 ret =re.sub( ' 正则表达式 ' , ' 要替换的结果 ' , ' 要匹配的字符串' , 要替换的数量 )
返回值 print( ret ) ===> ( '' 结果 '' , 替换的次数 ) 若没有替换 次数则为 0
e.g ret = re.sub( ' \d+ ' , ' H ' , ' 1457jhuuh5866' )
print(ret) ===> HHHHjhuuhHHHH
ret = re.subn( ' \d+ ' , ' 1457jhuuh5866' )
print( ret ) ===> ( ' HHHHjhuuhHHHH' , 8 )
切割***
split*** 返回的是切割后的列表 若没有符合正则的 则是一个列表中 是 原来的字符串 列表
语法 ret = re.split( ' 正则表达式 ' , '' 要切割的 字符串 '' )
返回值 print( ret ) ==> [ '' '' , '' '' , '' '' ] 或 [ ' 原来字符串 ' ]
e.g ret = re.split( '' \d+ '' , ' alex83taibai85 ' )
print( ret ) ===> [ '' alex '' , '' taibai '' , '' '' ] #因为最后是一个数字 所以列表最后 是一个空字符
进阶方法 ***** 爬虫\ 自动化开发
compile ***** 提高时间效率 节省时间
在 findall 中 是先将正则表达式 变成 pyhon能理解的 代码 , 然后 再去 执行代码
若只用一次 , 不节省时间
只有在多次使用某一个 相同的正则表达式 的时候 这个 compile 才会帮助我们 提高程序的效率 节省时间
语法 ret = re.compile( '' 正则表达式 '' )
ret1 = ret.search( '' 要匹配的字符串 '' )
返回值 print( ret1.group() ) 拿到 第一个 符合 正则的 匹配对象
若无匹配项 则返回 None
e.g ret = re.compile( ' 负数的正则表达式 '' )
ret1 = ret.search( '' jgrugh-5gjeeg9-41bg '' )
print( ret1.group() ) ===> -5
ret2 = ret.search( '' jguheufhe '' )
print(ret2) ===> None 报错
finditer ***** 提高空间效率 节省内存
findall 是将 符合正则的匹配项 全部放到 一个列表中 太占内存
而 finditer 是将列表变为一个 迭代器 可以 一个一个拿 节省内存
语法 ret = re.finditer( '' 正则表达式 '' , '' 要匹配的字符串 '' )
for r in ret :
print( r.group() ) # 拿到 每一个值
e.g ret = re . finditer( '' 负数的正则表达式 '' , '' gjgj-85hfgf-58yfy85 '' )
for r in ret:
print(r.group()) ===> -85 -58
python中的正则表达式
在正则表达式中 遇见分组 的特殊 方法
findall 会优先显示分组中的内容 , 要想取消分组优先 则 (?:正则表达式)
e.g ret=re.findall(r'\d+(?:\.\d+)|(\d+)','1-2*(60+(-40.35/5)-(-4*3))')
正则表达式 : 前边是 小数的表达式 | 整数的表达式 表示 小数或整数都可以
但是 后边 整数表达式 用分组括起来了 表示 优先显示分组中的 整数
即便是有小数也不让其显示出来,
因此 匹配项是 数字 但是小数没有显示出来 所以就是 一个空的字符
print(ret) ===> [ '1', '2', '60', ' ', '5', '4', '3']
ret.remove(" ") 将列表中的空格字符删去
print( ret ) ===> [ '1', '2', '60', '5', '4', '3'] 得到最后的结果
split 遇到分组会保留分组内被 切掉的内容
e.g
search 如果 search 中有分组的话 , 通过 group(n) 就能拿到 group中的 匹配项的内容
即 可以拿到 n 对应的第n个分组中的 匹配项
e.g ret = re.search( '' \d+(.\d+)(.\d+)(.\d+)? '' , '' 1.2.3.4-2*(60+(-40.35/5)-(-4*3)) '' )
print(ret.group()) ===> 1.2.3.4 # 匹配项
print(ret.group( 0 )) ===> 1.2.3.4
print(ret.group( 1 )) ===> .2 # 对应第n个分组 中的 匹配项
print(ret.group( 2 )) ====> .3
print(ret.group( 3 )) ====> .4
分组命名
我们可以通过 对 分组命名将 分组中的匹配项匹配出来
方法一 : 方便常用
( ?P< 名字name > 正则表达式 ) 再再后边使用 同分组内容的的时候
可以 ( ?P=名字name ) 表示和前边同名分组内容一摸一样的 分组内容
显示分组中内容的时候可以 print(ret.group( '' 名字name '' ))
方法二 : 不推荐经常用的
( 正则表达式 ) 再使用 这个分组的时候 可以 用 \ n 来表示 n表示 第几个分组
内容也是一模一样才可以
显示分组中的内容的时候 print(ret.group( n ))
e.g
ret = re.search ( '' < (?P<name>\w+)>\w+</(?P=name)> '' , '' <h1>hello<h1> '' )
print(ret.group('name')) # 得到 分组name中的匹配项 h1
print( ret.group() ) # 得到结果 <h1>hello<h1>
ret = re.search ( '' < (\w+)>\w+</ \ 1 > '' , '' <h1>hello<h1> '' )
print(ret.group(1)) # 得到 第一个 分组中的匹配项 h1
print( ret.group() ) # 得到结果 <h1>hello<h1>
当然 也可以对不同的组分别命名 , 从而得到 各个分组中的 匹配项
import random 模块
随机 : 在某个范围内取到的每一个值得概率相同
随机小数
语法 : print( random.random() ) 0 到 1 内的随机小数
print( random.uniform( n , m ) ) n到m 之内的任意小数
随机整数
语法 print( random.randint( n , m ) ) [ n , m ] 之间的随机整数 闭区间
print( randon.randrange( n , m ) ) [ n , m ) 之间的随机整数 不带 m
print( random.randrange( n, m, a) ) [ n , m) 之间 每a 个找一个的随机整数
随机抽取
lst= [ ... ]
ret = random.choice( lst )
print( ret ) 随机抽取一个值
ret = random.sample( lst , n)
print( ret ) 随机抽取n个
打乱顺序
random.shuffle( lst )
print( lst ) 在原列表上 打乱 lst 的 顺序
抽奖 \ 彩票\ 发红包\验证码
e.g 4位验证码 数字
def rand_code( n=4 ) :
code = '' ''
for i in range( n ):
num = random.randint( 0 , 9 )
code = code + str( num )
return code
print( rand_code() ) # 默认调用 函数 得到 四位的 数字验证码
print( rand_code( 6 ) ) # 传个参数 得到 参数位的 数字验证码
e.g 数字 / 字母 验证码 6 位
def rand_code( n=6 , als = True ) :
code = '' ''
for i in range ( n ) :
rand_int =str( random.randint( 0 , 9 ))
if als : # 当 als 为 False 时 不执行 只能得到 数字的验证码
rand_alp = chr (random.randint( 97 , 122 ))
rand_alo = chr (random.randint( 65, 90 ))
rand_int = random.choice( [ rand_alp , rand_int , rand_alo ] )
code = code+rand_int
return code
ret = rand_code( n = 4 ) 传参数 可以得到 任意位的验证码
print( ret )