模块(一)

os/time/datetime/random/json/pickle/re

os模块

os模块是与操作系统交互的一个接口

#当前执行这个python文件的工作目录相关的工作路径

os.getcwd() 获取当前工作目录,即当前python脚本工作的目录路径
os.chdir("dirname")  改变当前脚本工作目录;相当于shell下cd
os.curdir  返回当前目录: ('.')
os.pardir  获取当前目录的父目录字符串名:('..')


#和文件夹相关
os.makedirs('dirname1/dirname2')    可生成多层递归目录
os.removedirs('dirname1')    若目录为空,则删除,并递归到上一级目录,如若也为空,则删除,依此类推
os.mkdir('dirname')    生成单级目录;相当于shell中mkdir dirname
os.rmdir('dirname')    删除单级空目录,若目录不为空则无法删除,报错;相当于shell中rmdir dirname
os.listdir('dirname')    列出指定目录下的所有文件和子目录,包括隐藏文件,并以列表方式打印

# 和文件相关
os.remove()  删除一个文件
os.rename("oldname","newname")  重命名文件/目录
os.stat('path/filename')  获取文件/目录信息


# 和操作系统差异相关
os.sep    输出操作系统特定的路径分隔符,win下为"\\",Linux下为"/"
os.linesep    输出当前平台使用的行终止符,win下为"\t\n",Linux下为"\n"
os.pathsep    输出用于分割文件路径的字符串 win下为;,Linux下为:
os.name    输出字符串指示当前使用平台。win->'nt'; Linux->'posix'


# 和执行系统命令相关
os.system("bash command")  运行shell命令,直接显示
os.popen("bash command).read()  运行shell命令,获取执行结果
os.environ  获取系统环境变量


#path系列,和路径相关
os.path.abspath(path) 返回path规范化的绝对路径
os.path.split(path) 将path分割成目录和文件名二元组返回
os.path.dirname(path) 返回path的目录。其实就是os.path.split(path)的第一个元素
os.path.basename(path) 返回path最后的文件名。如何path以/或\结尾,那么就会返回空值,即os.path.split(path)的第二个元素。
os.path.exists(path)  如果path存在,返回True;如果path不存在,返回False
os.path.isabs(path)  如果path是绝对路径,返回True
os.path.isfile(path)  如果path是一个存在的文件,返回True。否则返回False
os.path.isdir(path)  如果path是一个存在的目录,则返回True。否则返回False
os.path.join(path1[, path2[, ...]])  将多个路径组合后返回,第一个绝对路径之前的参数将被忽略
os.path.getatime(path)  返回path所指向的文件或者目录的最后访问时间
os.path.getmtime(path)  返回path所指向的文件或者目录的最后修改时间
os.path.getsize(path) 返回path的大小


注意:os.stat('path/filename') 获取文件/目录信息 的结构说明



stat 结构:

st_mode: inode 保护模式
st_ino: inode 节点号。
st_dev: inode 驻留的设备。
st_nlink: inode 的链接数。
st_uid: 所有者的用户ID。
st_gid: 所有者的组ID。
st_size: 普通文件以字节为单位的大小;包含等待某些特殊文件的数据。
st_atime: 上次访问的时间。
st_mtime: 最后一次修改的时间。
st_ctime: 由操作系统报告的"ctime"。在某些系统上(如Unix)是最新的元数据更改的时间,在其它系统上(如Windows)是创建时间(详细信息参见平台的文档)。


sys模块

sys模块是与python解释器交互的一个接口
sys.argv           命令行参数List,第一个元素是程序本身路径
sys.exit(n)        退出程序,正常退出时exit(0),错误退出sys.exit(1)
sys.version        获取Python解释程序的版本信息
sys.path           返回模块的搜索路径,初始化时使用PYTHONPATH环境变量的值
sys.platform       返回操作系统平台名称


import sys
try:
    sys.exit(1)
except SystemExit as e:
    print(e)

time模块

时间模块里面有时间戳、格式化时间对象、时间字符串

import time
# 时间戳
print(time.time())               # 1587642175.403718

​# 格式化时间对象
print(time.gmtime())             # 格林尼治时间对象
print(time.localtime())          # 本地时间对象

显示结果:
time.struct_time(tm_year=2020, tm_mon=4, tm_mday=23, tm_hour=11, tm_min=45, tm_sec=52, tm_wday=3, tm_yday=114, tm_isdst=0)
time.struct_time(tm_year=2020, tm_mon=4, tm_mday=23, tm_hour=19, tm_min=45, tm_sec=52, tm_wday=3, tm_yday=114, tm_isdst=0)

# 时间字符串:
print(time.strftime('Year:%Y Month:%m Day:%d %H:%M:%S'))            # Year:2020 Month:04 Day:23 19:49:52
print(time.strftime('%Y-%m-%d %H:%M:%S'))            # 2020-04-23 19:51:01

时间戳、格式化时间对象、时间字符串之间的转换

# 时间戳 ------> 格式化时间对象   gmtime  localtime
print(time.localtime(time.time()))
# time.struct_time(tm_year=2020, tm_mon=4, tm_mday=23, tm_hour=19, tm_min=52, tm_sec=38, tm_wday=3, tm_yday=114, tm_isdst=0)

# 格式化时间对象 ------------> 时间戳       mktime
print(time.mktime(time.localtime()))              # 1587643045.0

# 格式化时间对象 ------------ > 时间字符串     strftime
print(time.strftime('%Y-%m-%d %H:%M:%S',time.localtime()))          # 2020-04-23 19:59:33

# 时间字符串   ---------------> 格式化时间对象   strptime
print(time.strptime('2020-10-20 18:20:20',"%Y-%m-%d %H:%M:%S"))
# time.struct_time(tm_year=2020, tm_mon=10, tm_mday=20, tm_hour=18, tm_min=20, tm_sec=20, tm_wday=1, tm_yday=294, tm_isdst=-1)

random模块

# random   默认是在[0,1)中间取一个浮点数
import random
print(random.random())            # 0.7630566252209585

# randomrange 取指定区间的整数
print(random.randrange(20,22))       # 20

# 取指定区间的浮点数 2<=x<3
print(random.uniform(2,3))          # 2.6726281613292175

# randomrange 取指定区间的整数
print(random.randint(10,30))

# 练习题: 判断哪一年的2月有多少天
import datetime
year = input('请输入一个年份:')
if year.strip().isdecimal():
    td = datetime.timedelta(days=1)
    d = datetime.date(int(year.strip()),3,1)
    new_d = d - td
    print(new_d.day)

datetime模块

import datetime
# datetime.date
d = datetime.date(2010,10,10)
print(d.year)              # 2010
print(d.month)             # 10
print(d.day)               # 10


# datetime.time
t = datetime.time(20,12,58)
print(t.hour)              # 20
print(t.minute)            # 12
print(t.second)            # 58


# datetime.datetime
dt = datetime.datetime(2010,12,12,12,12,35)
print(dt.second)         # 35
print(dt.hour)           # 12
print(dt.day)            # 12

# datetime.timedelta          一个时间段
td = datetime.timedelta(days=2)
dt = datetime.datetime(2020,4,23,10,20,30)
new_dt = dt +td
print(new_dt)

json、pickle模块

  • 序列化 将一个数据结构(list,str,tuple,dict,set..)转化成特殊的序列。

  • 反序列化 将这个特殊的序列反转回原来的数据结构。 特殊的序列:(特殊的字符串,bytes)

  • 为什么要有序列化模块 序列化 ---》 bytes:文件的存储,网络的传输 ++ dic = {'username':'alex','password':123}为什么不将这个dic存储在文件中? 文件存储不方便。

  • 为什么存在序列化 数据 ---》bytes 只有字符串类型和bytes可以互通 dict,list..... ------> str ------> bytes 数据存储在文件中,str(bytes)形式存储,比如字典 数据通过网络传输(bytes类型),str不能还原回去 特殊字符串:序列化。

  • 序列化模块: json pickle json模块(重点)

    • 1、不同语言都遵循的一种数据转化格式,即不同语言都使用的特殊字符串,(比如python的一个列表[1,2,3]) 利用json转化成特殊的字符串,然后在编码成bytes发送给php的开发者,php的开发者就可以编码成特殊的字符串,然后反解成原数组(列表):[1,2,3]

    • 2、json序列化只支持部分python数据结构:dict,list,tuple,str,int,float,True,False,None

    pickle模块

    • 1、只能是python语言遵循的一种数据转化格式,只能在python语言中使用

    • 2、支持python所有的数据类型包括实例化对象。

import json

import json
# s = json.dumps([1,3,4])
# print(type(s))           # <class 'str'>
# print(s)                 #  '[1,3,4]'

# res = json.dumps((1,2,3))
# print(res)                # '[1, 2, 3]'


# res = json.dumps({'name':'alex','age':10})
# print(res)                  # '{"name": "alex", "age": 10}'

# dump使用场景
# with open('a.txt','at',encoding='utf-8') as f:
#     json.dump([1,3,5],f)

# 反序列化
# 列表
# ret = json.dumps([1,3,7])
# lst = json.loads(ret)
# print(type(lst))              # <class 'list'>
# print(lst)                    # [1, 3, 7]

# 元祖
# res = json.dumps((1,3,7))
# lst1 = json.loads(res)
# print(type(lst1))             # <class 'list'>
# print(lst1)                   # [1, 3, 7]

# 文件
# with open('a.txt','r',encoding='utf-8') as f:
#     res = json.load(f)
#     print(type(res))             # <class 'list'>
#     print(res)                   # [1, 3, 5]

#把需要序列化的对象,通过多次序列化的方式,用文件的write的方法,把多次序列化后的json字符串写到文件中
# 1、先写入多个序列化的字符串到a.txt文件中
# with open('a.txt','at',encoding='utf-8') as f:
#     res1 = json.dumps([1,3,4])+'\n'
#     f.write(res1)
#     res2 = json.dumps([2,6,4])+'\n'
#     f.write(res2)
#
# # 2、从文件中一次多个反序列化出来
# with open('a.txt','r',encoding='utf-8') as f:
#     for i in f:
#         res = json.loads(i.strip())
#         print(res)                   # [1, 3, 4]   [2, 6, 4]

# pickle模块

# 1、pickle序列化出来的是二进制数据
import pickle

# 列表
# ret = pickle.dumps([1,3,5])
# print(ret)                               # b'\x80\x03]q\x00(K\x01K\x03K\x05e.'
#
# res = pickle.loads(ret)
# print(res)              # [1,3,5]
# print(type(res))        # <class 'list'>

# 2、pickle可以序列化任何数据类型的数据
# 元祖
# 序列化
# ret = pickle.dumps((1,3,5))
# print(ret)                                  # b'\x80\x03K\x01K\x03K\x05\x87q\x00.'
#
# # 反序列化
# res = pickle.loads(ret)
# print(res)                                 # (1, 3, 5)
# print(type(res))                           # <class 'tuple'>

# 集合的序列化和反序列化
#
# ret = pickle.dumps({'name','age','alex',1,7})
# print(ret)
# # b'\x80\x03cbuiltins\nset\nq\x00]q\x01(K\x01K\x07X\x04\x00\x00\x00alexq\x02X\x03\x00\x00\x00ageq\x03X\x04\x00\x00\x00nameq\x04e\x85q\x05Rq\x06.'
#
# res = pickle.loads(ret)
# print(res)
# # {1, 7, 'alex', 'name', 'age'}
# print(type(res))               # <class 'set'>

# pickle对文件的操作
# with open('a.txt','wb') as f:
#     pickle.dump([1,3,8],f)
#
# with open('a.txt','rb') as f:
#     res = pickle.load(f)
#     print(res)               # [1, 3, 8]
#     print(type(res))         # <class 'list'>


# pickle对一个文件进行多少操作
with open('a.txt','ab') as f:
    pickle.dump([1,3,7],f)
    pickle.dump([2,3,9],f)

with open('a.txt','rb') as f:
    for i in range(2):
        print(pickle.load(f))

re模块

这是京东的注册页面,打开页面我们就看到这些要求输入个人信息的提示。
假如我们随意的在手机号码这一栏输入一个11111111111,它会提示我们格式有误。
这个功能是怎么实现的呢?
假如现在你用python写一段代码,类似:

phone_number = input('please input your phone number : ')

你怎么判断这个phone_number是合法的呢?

根据手机号码一共11位并且是只以13、14、15、18开头的数字这些特点,我们用python写了如下代码:
while True:
    phone_number = input('please input your phone number : ')
    if len(phone_number) == 11 \
            and phone_number.isdigit()\
            and (phone_number.startswith('13') \
            or phone_number.startswith('14') \
            or phone_number.startswith('15') \
            or phone_number.startswith('18')):
        print('是合法的手机号码')
    else:
        print('不是合法的手机号码')
这是你的写法,现在我要展示一下我的写法

import re
phone_number = input('please input your phone number : ')
if re.match('^(13|14|15|18)[0-9]{9}$',phone_number):
        print('是合法的手机号码')
else:
        print('不是合法的手机号码')

对比上面的两种写法,此时此刻,我要问你你喜欢哪种方法呀?你肯定还是会说第一种,为什么呢?因为第一种不用学呀!
但是如果现在有一个文件,我让你从整个文件里匹配出所有的手机号码。你用python给我写个试试?
但是学了今天的技能之后,分分钟帮你搞定!

今天我们要学习python里的re模块和正则表达式,学会了这个就可以帮我们解决刚刚的疑问。正则表达式不仅在python领域,在整个编程届都占有举足轻重的地位。

不管以后你是不是去做python开发,只要你是一个程序员就应该了解正则表达式的基本使用。如果未来你要在爬虫领域发展,你就更应该好好学习这方面的知识。
但是你要知道,re模块本质上和正则表达式没有一毛钱的关系。re模块和正则表达式的关系 类似于 time模块和时间的关系
你没有学习python之前,也不知道有一个time模块,但是你已经认识时间了 12:30就表示中午十二点半(这个时间可好,一般这会儿就该下课了)。
时间有自己的格式,年月日时分秒,12个月,365天......已经成为了一种规则。你也早就牢记于心了。time模块只不过是python提供给我们的可以方便我们操作时间的一个工具而已

正则表达式本身也和python没有什么关系,就是匹配字符串内容的一种规则

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

正则表达式

一说规则我已经知道你很晕了,现在就让我们先来看一些实际的应用。在线测试工具 http://tool.chinaz.com/regex/

首先你要知道的是,谈到正则,就只和字符串相关了。在我给你提供的工具中,你输入的每一个字都是一个字符串。
其次,如果在一个位置的一个值,不会出现什么变化,那么是不需要规则的。
  比如你要用"1"去匹配"1",或者用"2"去匹配"2",直接就可以匹配上。这连python的字符串操作都可以轻松做到。
那么在之后我们更多要考虑的是在同一个位置上可以出现的字符的范围。
字符组 : [字符组]
在同一个位置可能出现的各种字符组成了一个字符组,在正则表达式中用[]表示
字符分为很多类,比如数字、字母、标点等等。
假如你现在要求一个位置"只能出现一个数字",那么这个位置上的字符只能是0、1、2...9这10个数之一。
正则 待匹配字符 匹配字符 说明
[0123456789]
8
True
在一个字符组里枚举合法的所有字符,字符组里的任意一个字符
和"待匹配字符"相同都视为可以匹配
[0123456789]
a False
由于字符组中没有"a"字符,所以不能匹配
[0-9] 7 True

也可以用-表示范围,[0-9]就和[0123456789]是一个意思
[a-z] s True
同样的如果要匹配所有的小写字母,直接用[a-z]就可以表示
[A-Z] B True
[A-Z]就表示所有的大写字母
[0-9A-Za-z] e True
可以匹配数字,大小写形式的a~f,用来验证十六进制字符

字符:

元字符 匹配内容
. 匹配除换行符以为的任意字符
\w 匹配字母或数字或下划线
\s 匹配任意的空白字符
\d 匹配任意的数字
\n 匹配一个换行符
\t 匹配一个制表符
\b 匹配一个单词的结尾
$ 匹配字符串的结束
^ 匹配字符串的开始
\W 匹配非字母或数字或下划线
\D 匹配非数字
\S 匹配非空白符
a|b 匹配字符a或者字符b
() 匹配括号内的表达式,也表示一个组
[…] 匹配字符串中的字符
[^…] 匹配除了字符组中字符的所有字符

量词:

量词 用法说明
* 重复零次或更多次
+ 重复一次或更多次

重复零次或一次
{n} 重复n次
{n,} 重复n次或更多次
{n,m}

重复n到m次

.^$

正则 待匹配字符 匹配结果 说明
海. 海燕海娇海东 海燕海娇海东 匹配有”海.”的字符
^海. 海燕海娇海东 海燕 从头开始匹配”海.”
海.$ 海燕海娇海东 海东 只匹配结尾的”海.$”

*+?{}

正则 待匹配字符 匹配结果 说明
李.? 李杰和李莲英和李二棍子 李杰李莲李二
?表示重复零次或一次,即只匹配"李"后面个任意字符
李.*

李杰和李莲英和李二棍子

李杰和李莲英和李二棍子
*表示重复零次或多次,即匹配"李"后面0或多个任意字符
李.+

李杰和李莲英和李二棍子

李杰和李莲英和李二棍子 +表示重复一次或多次,即匹配”李”后面1个或多个任意字符
李.{1,2} 李杰和李莲英和李二棍子 李杰和  李莲英 李二棍 {1,2}匹配1到2次任意字符

注意:前面的*,+,?等都是贪婪匹配,也就是尽肯能多的匹配,后面加?使其变成惰性匹配。

正则 待匹配字符 匹配结果 说明

李.+?

李杰和李莲英和李二棍子

李杰

李莲

李二

惰性匹配

李.*?

李杰和李莲英和李二棍子

惰性匹配

字符集 [] [^]

正则 待匹配字符 匹配结果 说明
李[杰莲英二棍子]* 李杰和李莲英和李二棍子

李杰  李莲英  李二棍子

表示匹配”李”后面[
杰莲英二棍子
]字符的任意字符
李[^和]* 李杰和李莲英和李二棍子 李杰  李莲英  李二棍子 表示匹配一个不是”和”的任意字符多次
[\d] 456bdha3 4  5 6 3 表示匹配任意一个数字,匹配到4个结果
[\d]+ 456bdha3 456  3 表示匹配任意个数字,匹配到2个结果

分组 ()与 或 |[^]

身份证号码是一个长度为15或18个字符的字符串,如果是15位则全部️数字组成,首位不能为0;如果是18位,则前17位全部是数字,末位可能是数字或x,下面我们尝试用正则来表示:

正则 待匹配字符 匹配结果 说明
^[1-9]\d{13,16}[0-9x]$ 110101198001017032 110101198001017032 表示可以匹配一个正确的身份证号
^[1-9]\d{13,16}[0-9x]$ 1101011980010170 1101011980010170
表示也可以匹配这串数字,但这并不是一个正确的身份证号码,它是一个16位的数字
^[1-9]\d{14}(\d{2}[0-9x])?$ 1101011980010170 False
现在不会匹配错误的身份证号了
()表示分组,将\d{2}[0-9x]分成一组,就可以整体约束他们出现的次数为0-1次
^([1-9]\d{16}[0-9x]|[1-9]\d{14})$ 110105199812067023 110105199812067023
表示先匹配[1-9]\d{16}[0-9x]如果没有匹配上就匹配[1-9]\d{14}


转义符 \

在正则表达式中,有很多有特殊意义的是元字符,比如\n和\s等,如果要在正则中匹配正常的"\n"而不是"换行符"就需要对"\"进行转义,变成'\\'。

在python中,无论是正则表达式,还是待匹配的内容,都是以字符串的形式出现的,在字符串中\也有特殊的含义,本身还需要转义。所以如果匹配一次"\n",字符串中要写成'\\n',那么正则里就要写成"\\\\n",这样就太麻烦了。这个时候我们就用到了r'\n'这个概念,此时的正则是r'\\n'就可以了。

正则 待匹配字符 匹配结果 说明
\n \n False
因为在正则表达式中\是有特殊意义的字符,所以要匹配\n本身,用表达式\n无法匹配
\\n \n True
转义\之后变成\\,即可匹配
“\\\\n” “\\n” True
如果在python中,字符串中的'\'也需要转义,所以每一个字符串'\'又需要转义一次
r”\\n” r”\n” True
在字符串之前加r,让整个字符串不转义

贪婪匹配

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

正则 待匹配字符 匹配结果 说明
<.*> <script>…<script> <script>…<script>
默认为贪婪匹配模式,会匹配尽量长的字符串
<.*?> <script>…<script> <script><script>
加上?为将贪婪匹配模式转为非贪婪匹配模式,会匹配尽量短的字符串
几个常用的非贪婪匹配Pattern
*? 重复任意次,但尽可能少重复
+? 重复1次或更多次,但尽可能少重复
?? 重复0次或1次,但尽可能少重复
{n,m}? 重复n到m次,但尽可能少重复
{n,}? 重复n次以上,但尽可能少重复
.*?的用法
. 是任意字符
* 是取 0 至 无限长度
? 是非贪婪模式。
何在一起就是 取尽量少的任意字符,一般不会这么单独写,他大多用在:
.*?x

就是取前面任意长度的字符,直到一个x出现

re模块下的常用方法


import re

ret = re.findall('a', 'eva egon yuan')  # 返回所有满足匹配条件的结果,放在列表里
print(ret) #结果 : ['a', 'a']

ret = re.search('a', 'eva egon yuan').group()
print(ret) #结果 : 'a'
# 函数会在字符串内查找模式匹配,只到找到第一个匹配然后返回一个包含匹配信息的对象,该对象可以
# 通过调用group()方法得到匹配的字符串,如果字符串没有匹配,则返回None。

ret = re.match('a', 'abc').group()  # 同search,不过尽在字符串开始处进行匹配
print(ret)
#结果 : 'a'

ret = re.split('[ab]', 'abcd')  # 先按'a'分割得到''和'bcd',在对''和'bcd'分别按'b'分割
print(ret)  # ['', '', 'cd']

ret = re.sub('\d', 'H', 'eva3egon4yuan4', 1)#将数字替换成'H',参数1表示只替换1个
print(ret) #evaHegon4yuan4

ret = re.subn('\d', 'H', 'eva3egon4yuan4')#将数字替换成'H',返回元组(替换的结果,替换了多少次)
print(ret)

obj = re.compile('\d{3}')  #将正则表达式编译成为一个 正则表达式对象,规则要匹配的是3个数字
ret = obj.search('abc123eeee') #正则表达式对象调用search,参数为待匹配的字符串
print(ret.group())  #结果 : 123

import re
ret = re.finditer('\d', 'ds3sy4784a')   #finditer返回一个存放匹配结果的迭代器
print(ret)  # <callable_iterator object at 0x10195f940>
print(next(ret).group())  #查看第一个结果
print(next(ret).group())  #查看第二个结果
print([i.group() for i in ret])  #查看剩余的左右结果


注意:

1 findall的优先级查询:


import re

ret = re.findall('www.(baidu|oldboy).com', 'www.oldboy.com')
print(ret)  # ['oldboy']     这是因为findall会优先把匹配结果组里内容返回,如果想要匹配结果,取消权限即可

ret = re.findall('www.(?:baidu|oldboy).com', 'www.oldboy.com')
print(ret)  # ['www.oldboy.com']


2 split的优先级查询


ret=re.split("\d+","eva3egon4yuan")
print(ret) #结果 : ['eva', 'egon', 'yuan']

ret=re.split("(\d+)","eva3egon4yuan")
print(ret) #结果 : ['eva', '3', 'egon', '4', 'yuan']
#在匹配部分加上()之后所切出的结果是不同的, #没有()的没有保留所匹配的项,但是有()的却能够保留了匹配的项, #这个在某些需要保留匹配部分的使用过程是非常重要的。


综合练习与扩展

1、匹配标签

import re


ret = re.search("<(?P<tag_name>\w+)>\w+</(?P=tag_name)>","<h1>hello</h1>")
#还可以在分组中利用?<name>的形式给分组起名字
#获取的匹配结果可以直接用group('名字')拿到对应的值
print(ret.group('tag_name'))  #结果 :h1
print(ret.group())  #结果 :<h1>hello</h1>

ret = re.search(r"<(\w+)>\w+</\1>","<h1>hello</h1>")
#如果不给组起名字,也可以用\序号来找到对应的组,表示要找的内容和前面的组内容一致
#获取的匹配结果可以直接用group(序号)拿到对应的值
print(ret.group(1))
print(ret.group())  #结果 :<h1>hello</h1>


2、匹配整数



import re

ret=re.findall(r"\d+","1-2*(60+(-40.35/5)-(-4*3))")
print(ret) #['1', '2', '60', '40', '35', '5', '4', '3']
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']

3、数字匹配

1、 匹配一段文本中的每行的邮箱
      http://blog.csdn.net/make164492212/article/details/51656638

2、 匹配一段文本中的每行的时间字符串,比如:‘1990-07-12’;

   分别取出1年的12个月(^(0?[1-9]|1[0-2])$)、
   一个月的31天:^((0?[1-9])|((1|2)[0-9])|30|31)$

3、 匹配qq号。(腾讯QQ号从10000开始)  [1,9][0,9]{4,}

4、 匹配一个浮点数。       ^(-?\d+)(\.\d+)?$   或者  -?\d+\.?\d*

5、 匹配汉字。             ^[\u4e00-\u9fa5]{0,}$

6、 匹配出所有整数


4、爬虫练习
import requests

import re
import json

def getPage(url):

    response=requests.get(url)
    return response.text

def parsePage(s):

    com=re.compile('<div class="item">.*?<div class="pic">.*?<em .*?>(?P<id>\d+).*?<span class="title">(?P<title>.*?)</span>'
                   '.*?<span class="rating_num" .*?>(?P<rating_num>.*?)</span>.*?<span>(?P<comment_num>.*?)评价</span>',re.S)

    ret=com.finditer(s)
    for i in ret:
        yield {
            "id":i.group("id"),
            "title":i.group("title"),
            "rating_num":i.group("rating_num"),
            "comment_num":i.group("comment_num"),
        }

def main(num):

    url='https://movie.douban.com/top250?start=%s&filter='%num
    response_html=getPage(url)
    ret=parsePage(response_html)
    print(ret)
    f=open("move_info7","a",encoding="utf8")

    for obj in ret:
        print(obj)
        data=json.dumps(obj,ensure_ascii=False)
        f.write(data+"\n")

if __name__ == '__main__':
    count=0
    for i in range(10):
        main(count)
        count+=25


import re
import json
from urllib.request import urlopen

def getPage(url):
    response = urlopen(url)
    return response.read().decode('utf-8')

def parsePage(s):
    com = re.compile(
        '<div class="item">.*?<div class="pic">.*?<em .*?>(?P<id>\d+).*?<span class="title">(?P<title>.*?)</span>'
        '.*?<span class="rating_num" .*?>(?P<rating_num>.*?)</span>.*?<span>(?P<comment_num>.*?)评价</span>', re.S)

    ret = com.finditer(s)
    for i in ret:
        yield {
            "id": i.group("id"),
            "title": i.group("title"),
            "rating_num": i.group("rating_num"),
            "comment_num": i.group("comment_num"),
        }


def main(num):
    url = 'https://movie.douban.com/top250?start=%s&filter=' % num
    response_html = getPage(url)
    ret = parsePage(response_html)
    print(ret)
    f = open("move_info7", "a", encoding="utf8")

    for obj in ret:
        print(obj)
        data = str(obj)
        f.write(data + "\n")

count = 0
for i in range(10):
    main(count)
    count += 25


flags有很多可选值:

re.I(IGNORECASE)忽略大小写,括号内是完整的写法
re.M(MULTILINE)多行模式,改变^和$的行为
re.S(DOTALL)点可以匹配任意字符,包括换行符
re.L(LOCALE)做本地化识别的匹配,表示特殊字符集 \w, \W, \b, \B, \s, \S 依赖于当前环境,不推荐使用
re.U(UNICODE) 使用\w \W \s \S \d \D使用取决于unicode定义的字符属性。在python3中默认使用该flag
re.X(VERBOSE)冗长模式,该模式下pattern字符串可以是多行的,忽略空白字符,并可以添加注释


作业

实现能计算类似 
1-2*((60-30+(-40/5)*(9-2*5/3+7/3*99/4*2998 +10 * 568/14))-(-4*3)/(16-3*2))
计算器:
import re

def mul_div(exp):
    # 计算乘除法
    if "*" in exp:
        a,b = exp.split('*')
        return float(a)*float(b)
    if '/' in exp:
        a,b = exp.split('/')
        return float(a)/float(b)

def all_add_sub(exp):
    # 计算所有的加减法
    # while 1:
    ret =  re.findall(r'[+\-]?\d+(?:\.\d+)?',exp)
    sum_all = 0
    for i in ret:
        sum_all += float(i)
    return sum_all

def remove_add_sub(exp):
    # 出现 +-或 -- 就要移除,不要影响后面的运算
    while 1:
        if '+-' in exp or '-+' in exp or '++' in exp or '--' in exp:
            exp = exp.replace('+-','-')
            exp = exp.replace('--','+')
            exp = exp.replace('-+','-')
            exp = exp.replace('++','+')
        else:
            break
    return exp

def all_mul_div(exp):
    # 计算所有的乘除法
    while 1:
        ret = re.search("\d+(\.\d+)?[*/][+-]?\d+(\.\d+)?",exp)    # 匹配 -6.23*4.18 这样的表达式
        # ret = re.search("[+\-]?\d+(\.\d+)?[*/]\d+(\.\d+)?",exp)
        if ret:
            son_exp = ret.group()
            res = mul_div(son_exp)
            exp = exp.replace(son_exp,str(res))
        else:
            break
    return exp


def remove_brackets(exp):
    # 计算括号里面的
    while 1:
        ret = re.search('\([^(|)]*\)',exp)
        if ret:
            son_exp = ret.group()
            new_exp = son_exp[1:-1]
            ret_exp = all_add_sub(remove_add_sub(all_mul_div(new_exp)))
            exp = exp.replace(son_exp,str(ret_exp))
        else:
            break
    return exp

def calc(exp):
    return all_add_sub(remove_add_sub(all_mul_div(remove_brackets(exp))))

exp = '1-2*((-60-30+(-40/5)*(9-2*5/3+7/3*99/4*2999+10*568/14))-(-4*3)/(16-3*2))+(45*3-25)-66+88'
ret = eval(exp)
print(ret)
print("=============")
ret1 = calc(exp)
print(ret1)



--------------------- end ---------------------------------------

posted @ 2020-04-23 20:20  全爱国  阅读(168)  评论(0编辑  收藏  举报