第三方模块

一,time模块

  • 时间戳(timestamp):通常来说,时间戳表示的是从1970年1月1日00:00:00开始按秒计算的偏移量。我们运行“type(time.time())”,返回的是float类型。
    • 作用:用于计算时间间隔的计算
  • 格式化的时间字符串(Format String)
    • 作用:展示时间
  • 结构化的时间(struct_time):struct_time元组共有9个元素共九个元素:(年,月,日,时,分,秒,一年中第几周,一年中第几天,夏令时)
    • 作用:用于展示部分时间
      1 import time
      2 print(time.time())#时间戳
      3 print(time.strftime("%Y-%m-%d %H:%M:%S %p"))#这个H可以换成I代表十二小时制,M代表二十四小时制,p代表上午与下午
      4 print(time.strftime("%Y-%m-%d %X")) #这个X与上面的%H:%M:%S是相同含义,这两个很重要
      1 import time
      2 res=time.localtime() #本地时区的struct_time
      3 print(res)    
      4 print(res.tm_year) 
      结构化时间

       

    进阶版:daetime模块

1 import datetime
2 print(datetime.datetime.now()) #直接展示当前时间
3 print(datetime.date.today()+datetime.timedelta(days=1)) #直接进行加减

      

 

1 #--------------------------按图1转换时间
 2 # localtime([secs])
 3 # 将一个时间戳转换为当前时区的struct_time。secs参数未提供,则以当前时间为准。
 4 time.localtime()
 5 time.localtime(1473525444.037215)
 6 
 7 # gmtime([secs]) 和localtime()方法类似,gmtime()方法是将一个时间戳转换为UTC时区(0时区)的struct_time。
 8 
 9 # mktime(t) : 将一个struct_time转化为时间戳。
10 print(time.mktime(time.localtime()))#1473525749.0
11 
12 
13 # strftime(format[, t]) : 把一个代表时间的元组或者struct_time(如由time.localtime()和
14 # time.gmtime()返回)转化为格式化的时间字符串。如果t未指定,将传入time.localtime()。如果元组中任何一个
15 # 元素越界,ValueError的错误将会被抛出。
16 print(time.strftime("%Y-%m-%d %X", time.localtime()))#2016-09-11 00:49:56
17 
18 # time.strptime(string[, format])
19 # 把一个格式化时间字符串转化为struct_time。实际上它和strftime()是逆操作。
20 print(time.strptime('2011-05-05 16:37:06', '%Y-%m-%d %X'))
21 #time.struct_time(tm_year=2011, tm_mon=5, tm_mday=5, tm_hour=16, tm_min=37, tm_sec=6,
22 #  tm_wday=3, tm_yday=125, tm_isdst=-1)
23 #在这个函数中,format默认为:"%a %b %d %H:%M:%S %Y"

 了解知识

1 import datetime
2 print(datetime.datetime.fromtimestamp(2233333)) #直接将时间戳转化为标准格式

二,random模块

 1 import random
 2  
 3 print(random.random())#(0,1)----float    大于0且小于1之间的小数
 4  
 5 print(random.randint(1,3))  #[1,3]    大于等于1且小于等于3之间的整数
 6  
 7 print(random.randrange(1,3)) #[1,3)    大于等于1且小于3之间的整数
 8  
 9 print(random.choice([1,'23',[4,5]]))#1或者23或者[4,5]
10  
11 print(random.sample([1,'23',[4,5]],2))#列表元素任意2个组合
12  
13 print(random.uniform(1,3))#大于1小于3的小数,如1.927109612082716 
14  
15  
16 item=[1,3,5,7,9]
17 random.shuffle(item) #打乱item的顺序,相当于"洗牌"
18 print(item)

应用:生成验证码

 1 import random
 2 def make_code(n):
 3     res=''
 4     for i in range(n):
 5         s1=chr(random.randint(65,90)) #代表ASCill验证码a-z
 6         s2=str(random.randint(0,9))
 7         res+=random.choice([s1,s2])
 8     return res
 9 
10 print(make_code(9))

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

 1 os.getcwd() 获取当前工作目录,即当前python脚本工作的目录路径
 2 os.chdir("dirname")  改变当前脚本工作目录;相当于shell下cd
 3 os.curdir  返回当前目录: ('.')
 4 os.pardir  获取当前目录的父目录字符串名:('..')
 5 os.makedirs('dirname1/dirname2')    可生成多层递归目录
 6 os.removedirs('dirname1')    若目录为空,则删除,并递归到上一级目录,如若也为空,则删除,依此类推
 7 os.mkdir('dirname')    生成单级目录;相当于shell中mkdir dirname
 8 os.rmdir('dirname')    删除单级空目录,若目录不为空则无法删除,报错;相当于shell中rmdir dirname
 9 os.listdir('dirname')    列出指定目录下的所有文件和子目录,包括隐藏文件,并以列表方式打印
10 os.remove()  删除一个文件
11 os.rename("oldname","newname")  重命名文件/目录
12 os.stat('path/filename')  获取文件/目录信息
13 os.sep    输出操作系统特定的路径分隔符,win下为"\\",Linux下为"/"
14 os.linesep    输出当前平台使用的行终止符,win下为"\t\n",Linux下为"\n"
15 os.pathsep    输出用于分割文件路径的字符串 win下为;,Linux下为:
16 os.name    输出字符串指示当前使用平台。win->'nt'; Linux->'posix'
17 os.system("bash command")  运行shell命令,直接显示
18 os.environ  获取系统环境变量
19 os.path.abspath(path)  返回path规范化的绝对路径
20 os.path.split(path)  将path分割成目录和文件名二元组返回
21 os.path.dirname(path)  返回path的目录。其实就是os.path.split(path)的第一个元素
22 os.path.basename(path)  返回path最后的文件名。如何path以/或\结尾,那么就会返回空值。即os.path.split(path)的第二个元素
23 os.path.exists(path)  如果path存在,返回True;如果path不存在,返回False
24 os.path.isabs(path)  如果path是绝对路径,返回True
25 os.path.isfile(path)  如果path是一个存在的文件,返回True。否则返回False
26 os.path.isdir(path)  如果path是一个存在的目录,则返回True。否则返回False
27 os.path.join(path1[, path2[, ...]])  将多个路径组合后返回,第一个绝对路径之前的参数将被忽略
28 os.path.getatime(path)  返回path所指向的文件或者目录的最后存取时间
29 os.path.getmtime(path)  返回path所指向的文件或者目录的最后修改时间
30 os.path.getsize(path) 返回path的大小
 1 在Linux和Mac平台上,该函数会原样返回path,在windows平台上会将路径中所有字符转换为小写,并将所有斜杠转换为饭斜杠。
 2 >>> os.path.normcase('c:/windows\\system32\\')   
 3 'c:\\windows\\system32\\'   
 4    
 5 
 6 规范化路径,如..和/
 7 >>> os.path.normpath('c://windows\\System32\\../Temp/')   
 8 'c:\\windows\\Temp'   
 9 
10 >>> a='/Users/jieli/test1/\\\a1/\\\\aa.py/../..'
11 >>> print(os.path.normpath(a))
12 /Users/jieli/test1

  路径处理:

 1 os路径处理
 2 #方式一:
 3 import os
 4 #具体应用
 5 import os,sys
 6 possible_topdir = os.path.normpath(os.path.join(
 7     os.path.abspath(__file__),
 8     os.pardir, #上一级
 9     os.pardir,
10     os.pardir
11 ))
12 sys.path.insert(0,possible_topdir)
13 
14 
15 #方式二:
16 os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

 四,sys模块

1 sys.argv           命令行参数List,第一个元素是程序本身路径
2 sys.exit(n)        退出程序,正常退出时exit(0)
3 sys.version        获取Python解释程序的版本信息
4 sys.maxint         最大的Int值
5 sys.path           返回模块的搜索路径,初始化时使用PYTHONPATH环境变量的值
6 sys.platform       返回操作系统平台名称

  重点掌握第1,5个

 五,shutil模块,有关文件移动的(了解)

高级的 文件、文件夹、压缩包 处理模块

shutil.copyfileobj(fsrc, fdst[, length])
将文件内容拷贝到另一个文件中

1 import shutil
2  
3 shutil.copyfileobj(open('old.xml','r'), open('new.xml', 'w'))

 

shutil.copyfile(src, dst)
拷贝文件

1 shutil.copyfile('f1.log', 'f2.log') #目标文件无需存在

 

shutil.copymode(src, dst)
仅拷贝权限。内容、组、用户均不变

1 shutil.copymode('f1.log', 'f2.log') #目标文件必须存在

 

shutil.copystat(src, dst)
仅拷贝状态的信息,包括:mode bits, atime, mtime, flags

1 shutil.copystat('f1.log', 'f2.log') #目标文件必须存在

 

shutil.copy(src, dst)
拷贝文件和权限

1 import shutil
2  
3 shutil.copy('f1.log', 'f2.log')

 

shutil.copy2(src, dst)
拷贝文件和状态信息

1 import shutil
2  
3 shutil.copy2('f1.log', 'f2.log')

 

shutil.ignore_patterns(*patterns)
shutil.copytree(src, dst, symlinks=False, ignore=None)
递归的去拷贝文件夹

1 import shutil
2  
3 shutil.copytree('folder1', 'folder2', ignore=shutil.ignore_patterns('*.pyc', 'tmp*')) #目标目录不能存在,注意对folder2目录父级目录要有可写权限,ignore的意思是排除 
 拷贝软连接

 

shutil.rmtree(path[, ignore_errors[, onerror]])
递归的去删除文件

1 import shutil
2  
3 shutil.rmtree('folder1')

 

shutil.move(src, dst)
递归的去移动文件,它类似mv命令,其实就是重命名。

1 import shutil
2  
3 shutil.move('folder1', 'folder3')

 

shutil.make_archive(base_name, format,...)

创建压缩包并返回文件路径,例如:zip、tar

创建压缩包并返回文件路径,例如:zip、tar

  • base_name: 压缩包的文件名,也可以是压缩包的路径。只是文件名时,则保存至当前目录,否则保存至指定路径,
    如 data_bak                       =>保存至当前路径
    如:/tmp/data_bak =>保存至/tmp/
  • format: 压缩包种类,“zip”, “tar”, “bztar”,“gztar”
  • root_dir: 要压缩的文件夹路径(默认当前目录)
  • owner: 用户,默认当前用户
  • group: 组,默认当前组
  • logger: 用于记录日志,通常是logging.Logger对象
复制代码
1 #将 /data 下的文件打包放置当前程序目录
2 import shutil
3 ret = shutil.make_archive("data_bak", 'gztar', root_dir='/data')
4   
5   
6 #将 /data下的文件打包放置 /tmp/目录
7 import shutil
8 ret = shutil.make_archive("/tmp/data_bak", 'gztar', root_dir='/data') 
复制代码

shutil 对压缩包的处理是调用 ZipFile 和 TarFile 两个模块来进行的,详细:

 zipfile压缩解压缩
 tarfile压缩解压缩

六 ,json&pickle模块,有关序列化的模块

  前期知识准备:

    序列化:

      内存中的数据模型--->序列化--->特定的格式(json格式或picket格式)

    反序列化:

      内存中的数据模型<---序列化<---特定的格式(json格式或picket格式)

    序列化作用:

      • 用于储存,常用的是pickle模块
        • 内存是无法永久保存数据的,当程序运行了一段时间,我们断电或者重启程序,内存中关于这个程序的之前一段时间的数据(有结构)都被清空了。

          在断电或重启程序之前将程序当前内存中所有的数据都保存下来(保存到文件中),以便于下次程序执行能够从文件中载入之前的数据,然后继续执行,这就是序列化。

          具体的来说,你玩使命召唤闯到了第13关,你保存游戏状态,关机走人,下次再玩,还能从上次的位置开始继续闯关。或如,虚拟机状态的挂起等。

      • 用于夸平台、跨语言的数据交互,常用的是json模块
        • 有时候写功能时,可能需要不同语言的结果进行交互,此时就需要一种中间结构的数据进行传输
      • 强调:虽然理论上json模块也可以用于储存,但是具有局限性,比如里面就没有集合的形式
      • json中的格式与python中有很类似的,但是还是不同的,注意区分
      •  

  具体操作:

1 s=[1,2,3,'aaa',['1',2,'b']]
2 import json
3 #序列化的复杂方法
4 with open('test.txt',mode='wt',encoding='utf-8') as f:
5     pre=json.dumps(s)
6     f.write(pre)
7 # 序列化的简单方法
8     json.dump(s,f)
9 反序列化也是类似的

  注意点:

    • 无论数据是怎样创建的,只要满足json格式,就可以json.loads出来,不一定非要dumps的数据才能loads
      1 import json
      2 #dct="{'1':111}"#json 不认单引号
      3 #dct=str({"1":111})#报错,因为生成的数据还是单引号:{'one': 1}
      4 
      5 dct='{"1":"111"}'
      6 print(json.loads(dct))
    • 在python解释器2.7与3.6之后都可以json.loads(bytes类型),但唯独3.5不可以
      1 >>> import json
      2 >>> json.loads(b'{"a":111}')
      3 Traceback (most recent call last):
      4   File "<stdin>", line 1, in <module>
      5   File "/Users/linhaifeng/anaconda3/lib/python3.5/json/__init__.py", line 312, in loads
      6     s.__class__.__name__))
      7 TypeError: the JSON object must be str, not 'bytes'

       

  猴子补丁,就是在原模块中对某一功能进行覆盖,不对原功能进行抹除。

  特点是如果之前即使进行了引用此次改动也不会影响到之前的。

 1 只需要在入口处加上
 2 , 只需要在入口加上:
 3 
 4 import json
 5 import ujson
 6 
 7 def monkey_patch_json():
 8     json.__name__ = 'ujson'
 9     json.dumps = ujson.dumps
10     json.loads = ujson.loads
11 
12 monkey_patch_json() # 之所以在入口处加,是因为模块在导入一次后,后续的导入便直接引用第一次的成果
13 
14 #其实这种场景也比较多, 比如我们引用团队通用库里的一个模块, 又想丰富模块的功能, 除了继承之外也可以考虑用Monkey
15 Patch.采用猴子补丁之后,如果发现ujson不符合预期,那也可以快速撤掉补丁。个人感觉Monkey
16 Patch带了便利的同时也有搞乱源代码的风险!

七, shelve模块(了解)与xml模块(了解)

 shelve模块比pickle模块简单,只有一个open函数,返回类似字典的对象,可读可写;key必须为字符串,而值可以是python所支持的数据类型

复制代码
import shelve

f=shelve.open(r'sheve.txt')
# f['stu1_info']={'name':'egon','age':18,'hobby':['piao','smoking','drinking']}
# f['stu2_info']={'name':'gangdan','age':53}
# f['school_info']={'website':'http://www.pypy.org','city':'beijing'}

print(f['stu1_info']['hobby'])
f.close()
复制代码

xml是实现不同语言或程序之间进行数据交换的协议,跟json差不多,但json使用起来更简单,不过,古时候,在json还没诞生的黑暗年代,大家只能选择用xml呀,至今很多传统公司如金融行业的很多系统的接口还主要是xml。

xml的格式如下,就是通过<>节点来区别数据结构的:

复制代码
<?xml version="1.0"?>
<data>
    <country name="Liechtenstein">
        <rank updated="yes">2</rank>
        <year>2008</year>
        <gdppc>141100</gdppc>
        <neighbor name="Austria" direction="E"/>
        <neighbor name="Switzerland" direction="W"/>
    </country>
    <country name="Singapore">
        <rank updated="yes">5</rank>
        <year>2011</year>
        <gdppc>59900</gdppc>
        <neighbor name="Malaysia" direction="N"/>
    </country>
    <country name="Panama">
        <rank updated="yes">69</rank>
        <year>2011</year>
        <gdppc>13600</gdppc>
        <neighbor name="Costa Rica" direction="W"/>
        <neighbor name="Colombia" direction="E"/>
    </country>
</data>
复制代码

xml协议在各个语言里的都 是支持的,在python中可以用以下模块操作xml:

# print(root.iter('year')) #全文搜索
# print(root.find('country')) #在root的子节点找,只找一个
# print(root.findall('country')) #在root的子节点找,找所有

 

复制代码
import xml.etree.ElementTree as ET
 
tree = ET.parse("xmltest.xml")
root = tree.getroot()
print(root.tag)
 
#遍历xml文档
for child in root:
    print('========>',child.tag,child.attrib,child.attrib['name'])
    for i in child:
        print(i.tag,i.attrib,i.text)
 
#只遍历year 节点
for node in root.iter('year'):
    print(node.tag,node.text)
#---------------------------------------

import xml.etree.ElementTree as ET
 
tree = ET.parse("xmltest.xml")
root = tree.getroot()
 
#修改
for node in root.iter('year'):
    new_year=int(node.text)+1
    node.text=str(new_year)
    node.set('updated','yes')
    node.set('version','1.0')
tree.write('test.xml')
 
 
#删除node
for country in root.findall('country'):
   rank = int(country.find('rank').text)
   if rank > 50:
     root.remove(country)
 
tree.write('output.xml')
复制代码
复制代码
#在country内添加(append)节点year2
import xml.etree.ElementTree as ET
tree = ET.parse("a.xml")
root=tree.getroot()
for country in root.findall('country'):
    for year in country.findall('year'):
        if int(year.text) > 2000:
            year2=ET.Element('year2')
            year2.text='新年'
            year2.attrib={'update':'yes'}
            country.append(year2) #往country节点下添加子节点

tree.write('a.xml.swap')
复制代码

自己创建xml文档:

 1 import xml.etree.ElementTree as ET
 2  
 3  
 4 new_xml = ET.Element("namelist")
 5 name = ET.SubElement(new_xml,"name",attrib={"enrolled":"yes"})
 6 age = ET.SubElement(name,"age",attrib={"checked":"no"})
 7 sex = ET.SubElement(name,"sex")
 8 sex.text = '33'
 9 name2 = ET.SubElement(new_xml,"name",attrib={"enrolled":"no"})
10 age = ET.SubElement(name2,"age")
11 age.text = '19'
12  
13 et = ET.ElementTree(new_xml) #生成文档对象
14 et.write("test.xml", encoding="utf-8",xml_declaration=True)
15  
16 ET.dump(new_xml) #打印生成的格式

八,configparser模块,有关配置文件的模块

 1 # 注释1
 2 ; 注释2
 3 
 4 [section1] #代表一部分的意思
 5 k1 = v1
 6 k2:v2
 7 user=egon
 8 age=18
 9 is_admin=true
10 salary=31
11 
12 [section2]
13 k1 = v1

读取

 1 import configparser
 2 
 3 config=configparser.ConfigParser()
 4 config.read('a.cfg')
 5 
 6 #查看所有的标题
 7 res=config.sections() #['section1', 'section2']
 8 print(res)
 9 
10 #查看标题section1下所有key=value的key
11 options=config.options('section1')
12 print(options) #['k1', 'k2', 'user', 'age', 'is_admin', 'salary']
13 
14 #查看标题section1下所有key=value的(key,value)格式
15 item_list=config.items('section1')
16 print(item_list) #[('k1', 'v1'), ('k2', 'v2'), ('user', 'egon'), ('age', '18'), ('is_admin', 'true'), ('salary', '31')]
17 
18 #查看标题section1下user的值=>字符串格式
19 val=config.get('section1','user')
20 print(val) #egon
21 
22 #查看标题section1下age的值=>整数格式
23 val1=config.getint('section1','age')
24 print(val1) #18
25 
26 #查看标题section1下is_admin的值=>布尔值格式
27 val2=config.getboolean('section1','is_admin')
28 print(val2) #True
29 
30 #查看标题section1下salary的值=>浮点型格式
31 val3=config.getfloat('section1','salary')
32 print(val3) #31.0

改写,一般改写是用户的事情

 1 import configparser
 2 
 3 config=configparser.ConfigParser()
 4 config.read('a.cfg',encoding='utf-8')
 5 
 6 
 7 #删除整个标题section2
 8 config.remove_section('section2')
 9 
10 #删除标题section1下的某个k1和k2
11 config.remove_option('section1','k1')
12 config.remove_option('section1','k2')
13 
14 #判断是否存在某个标题
15 print(config.has_section('section1'))
16 
17 #判断标题section1下是否有user
18 print(config.has_option('section1',''))
19 
20 
21 #添加一个标题
22 config.add_section('egon')
23 
24 #在标题egon下添加name=egon,age=18的配置
25 config.set('egon','name','egon')
26 config.set('egon','age',18) #报错,必须是字符串
27 
28 
29 #最后将修改的内容写入文件,完成最终的修改
30 config.write(open('a.cfg','w'))

九,hashlib模块

  准备知识:

    1,hash是一类算法,该算法接受传入的内容经过运算得到的一串hash值

    2,特点

      • 只要传入的内容一样,得到的hash值就一样
        • 应用点:可以检验下载的内容是否一样、文件是否被篡改
      • 不能hash值反解内容
        • 用于密码变成暗文
      • 只要使用的hash算法不变,无论内容有多大,达到的hash长度是固定的

  具体使用:hash算法就像一座工厂,工厂接收你送来的原材料(可以用m.update()为工厂运送原材料),经过加工返回的产品就是hash值

        

 

 1 import hashlib
 2  
 3 m=hashlib.md5()# m=hashlib.sha256() 
 4  
 5 m.update('hello'.encode('utf8'))#转化时必须要转为字节类型
 6 print(m.hexdigest())  #5d41402abc4b2a76b9719d911017c592
 7  
 8 m.update('alvin'.encode('utf8'))
 9  
10 print(m.hexdigest())  #92a7e713c30abbb0319fa07da2a5c4af
11  
12 m2=hashlib.md5()
13 m2.update('helloalvin'.encode('utf8'))
14 print(m2.hexdigest()) #92a7e713c30abbb0319fa07da2a5c4af
15 
16 '''
17 注意:把一段很长的数据update多次,与一次update这段长数据,得到的结果一样
18 但是update多次为校验大文件提供了可能。
19 '''
 1 import hashlib
 2 #第一种直接进行转化
 3 with open(r'C:\Users\dell',encoding='ab') as f:
 4     print(hashlib.md5(f.encode('utf-8')).hexdigest())
 5 #第二种可以防止文件太大导致内存出现问题
 6 with open(r'C:\Users\dell',encoding='ab') as f:
 7     m=''
 8     m=hashlib.md5()
 9     for i in f:
10         m.update(i.encode('utf-8'))
11     print(m.hexdigest())    
12 #第三种是随机抽取并进行验证       
13         
文件验证

  撞库是在一定程度上可以对暗文进行反解,所以可以使用加盐。加盐就是人为的加上一些数据使密码更加的复杂

1 import hashlib
2 #第一种直接进行转化
3 m=hashlib.md5()
4 m.update('hello'.encode('utf-8'))
5 m.update('你好'.encode('utf-8')) #在中间加
6 m.update('world'.encode('utf-8'))
7 print(m.hexdigest())

十,suprocess模块,可以拿到系统运行结果的一种模块

 import  subprocess
 2 #stout,代表正确结果,stderr代表错误结果
 3 '''
 4 sh-3.2# ls /Users/egon/Desktop |grep txt$
 5 mysql.txt
 6 tt.txt
 7 事物.txt
 8 '''
 9 
10 res1=subprocess.Popen('ls /Users/jieli/Desktop',shell=True,stdout=subprocess.PIPE)
11 res=subprocess.Popen('grep txt$',shell=True,stdin=res1.stdout,
12                  stdout=subprocess.PIPE)
13 
14 print(res.stdout.read().decode('utf-8'))
15 
16 
17 #等同于上面,但是上面的优势在于,一个数据流可以和另外一个数据流交互,可以通过爬虫得到结果然后交给grep
18 res1=subprocess.Popen('ls /Users/jieli/Desktop |grep txt$',shell=True,stdout=subprocess.PIPE)
19 print(res1.stdout.read().decode('utf-8'))
20 
21 
22 #windows下:
23 # dir | findstr 'test*'
24 # dir | findstr 'txt$'
25 import subprocess
26 res1=subprocess.Popen(r'dir C:\Users\Administrator\PycharmProjects\test\函数备课',shell=True,stdout=subprocess.PIPE)
27 res=subprocess.Popen('findstr test*',shell=True,stdin=res1.stdout,
28                  stdout=subprocess.PIPE)
29 
30 print(res.stdout.read().decode('gbk')) #subprocess使用当前系统默认编码,得到结果为bytes类型,在windows下需要用gbk解码

十一,logging模块

  1,日志级别

1 CRITICAL = 50 #FATAL = CRITICAL
2 ERROR = 40
3 WARNING = 30 #WARN = WARNING
4 INFO = 20
5 DEBUG = 10
6 NOTSET = 0 #不设置

 

  2,日志配置,可以直接粘贴复制

 1 import logging
 2 
 3 # 一:日志配置
 4 logging.basicConfig(
 5     # 1、日志输出位置:1、终端 2、文件
 6     # filename='access.log', # 不指定,默认打印到终端
 7 
 8     # 2、日志格式
 9     format='%(asctime)s - %(name)s - %(levelname)s -%(module)s:  %(message)s',
10 
11     # 3、时间格式
12     datefmt='%Y-%m-%d %H:%M:%S %p',
13 
14     # 4、日志级别
15     # critical => 50
16     # error => 40
17     # warning => 30
18     # info => 20
19     # debug => 10
20     level=30,
21 )
22 
23 # 二:输出日志
24 logging.debug('调试debug')
25 logging.info('消息info')
26 logging.warning('警告warn')
27 logging.error('错误error')
28 logging.critical('严重critical')
29 
30 '''
31 # 注意下面的root是默认的日志名字
32 WARNING:root:警告warn
33 ERROR:root:错误error
34 CRITICAL:root:严重critical
35 '''

   3,为logging模块指全局配置,针对所有logger有效,控制打印到文件中

 1 可在logging.basicConfig()函数中通过具体参数来更改logging模块默认行为,可用参数有
 2 filename:用指定的文件名创建FiledHandler(后边会具体讲解handler的概念),这样日志会被存储在指定的文件中。
 3 filemode:文件打开方式,在指定了filename时使用这个参数,默认值为“a”还可指定为“w”。
 4 format:指定handler使用的日志显示格式。 
 5 datefmt:指定日期时间格式。 
 6 level:设置rootlogger(后边会讲解具体概念)的日志级别 
 7 stream:用指定的stream创建StreamHandler。可以指定输出到sys.stderr,sys.stdout或者文件,默认为sys.stderr。若同时列出了filename和stream两个参数,则stream参数会被忽略。
 8 
 9 
10 
11 #格式
12 %(name)s:Logger的名字,并非用户名,详细查看
13 
14 %(levelno)s:数字形式的日志级别
15 
16 %(levelname)s:文本形式的日志级别
17 
18 %(pathname)s:调用日志输出函数的模块的完整路径名,可能没有
19 
20 %(filename)s:调用日志输出函数的模块的文件名
21 
22 %(module)s:调用日志输出函数的模块名
23 
24 %(funcName)s:调用日志输出函数的函数名
25 
26 %(lineno)d:调用日志输出函数的语句所在的代码行
27 
28 %(created)f:当前时间,用UNIX标准的表示时间的浮 点数表示
29 
30 %(relativeCreated)d:输出日志信息时的,自Logger创建以 来的毫秒数
31 
32 %(asctime)s:字符串形式的当前时间。默认格式是 “2003-07-08 16:49:45,896”。逗号后面的是毫秒
33 
34 %(thread)d:线程ID。可能没有
35 
36 %(threadName)s:线程名。可能没有
37 
38 %(process)d:进程ID。可能没有
39 
40 %(message)s:用户输出的消息
41 
42  
 1 复制代码
 2 #======介绍
 3 可在logging.basicConfig()函数中可通过具体参数来更改logging模块默认行为,可用参数有
 4 filename:用指定的文件名创建FiledHandler(后边会具体讲解handler的概念),这样日志会被存储在指定的文件中。
 5 filemode:文件打开方式,在指定了filename时使用这个参数,默认值为“a”还可指定为“w”。
 6 format:指定handler使用的日志显示格式。
 7 datefmt:指定日期时间格式。
 8 level:设置rootlogger(后边会讲解具体概念)的日志级别
 9 stream:用指定的stream创建StreamHandler。可以指定输出到sys.stderr,sys.stdout或者文件,默认为sys.stderr。若同时列出了filename和stream两个参数,则stream参数会被忽略。
10 
11 
12 format参数中可能用到的格式化串:
13 %(name)s Logger的名字
14 %(levelno)s 数字形式的日志级别
15 %(levelname)s 文本形式的日志级别
16 %(pathname)s 调用日志输出函数的模块的完整路径名,可能没有
17 %(filename)s 调用日志输出函数的模块的文件名
18 %(module)s 调用日志输出函数的模块名
19 %(funcName)s 调用日志输出函数的函数名
20 %(lineno)d 调用日志输出函数的语句所在的代码行
21 %(created)f 当前时间,用UNIX标准的表示时间的浮 点数表示
22 %(relativeCreated)d 输出日志信息时的,自Logger创建以 来的毫秒数
23 %(asctime)s 字符串形式的当前时间。默认格式是 “2003-07-08 16:49:45,896”。逗号后面的是毫秒
24 %(thread)d 线程ID。可能没有
25 %(threadName)s 线程名。可能没有
26 %(process)d 进程ID。可能没有
27 %(message)s用户输出的消息
28 
29 
30 
31 
32 #========使用
33 import logging
34 logging.basicConfig(filename='access.log',
35                     format='%(asctime)s - %(name)s - %(levelname)s -%(module)s:  %(message)s',
36                     datefmt='%Y-%m-%d %H:%M:%S %p',
37                     level=10)
38 
39 logging.debug('调试debug')
40 logging.info('消息info')
41 logging.warning('警告warn')
42 logging.error('错误error')
43 logging.critical('严重critical')
44 
45 
46 
47 
48 
49 #========结果
50 access.log内容:
51 2017-07-28 20:32:17 PM - root - DEBUG -test:  调试debug
52 2017-07-28 20:32:17 PM - root - INFO -test:  消息info
53 2017-07-28 20:32:17 PM - root - WARNING -test:  警告warn
54 2017-07-28 20:32:17 PM - root - ERROR -test:  错误error
55 2017-07-28 20:32:17 PM - root - CRITICAL -test:  严重critical
56 
57 part2: 可以为logging模块指定模块级的配置,即所有logger的配置

  4,logging模块的Formatter,Handler,Logger,Filter对象      

 

  

#logger:产生日志的对象

#Filter:过滤日志的对象

#Handler:接收日志然后控制打印到不同的地方,FileHandler用来打印到文件中,StreamHandler用来打印到终端

#Formatter对象:可以定制不同的日志格式对象,然后绑定给不同的Handler对象使用,以此来控制不同的Handler的日志格式

  5,Logger与Handler的级别

 1 Logger is also the first to filter the message based on a level — if you set the logger to INFO, and all handlers to DEBUG, you still won't receive DEBUG messages on handlers — they'll be rejected by the logger itself. If you set logger to DEBUG, but all handlers to INFO, you won't receive any DEBUG messages either — because while the logger says "ok, process this", the handlers reject it (DEBUG < INFO).
 2 
 3 
 4 
 5 #验证
 6 import logging
 7 
 8 
 9 form=logging.Formatter('%(asctime)s - %(name)s - %(levelname)s -%(module)s:  %(message)s',
10                     datefmt='%Y-%m-%d %H:%M:%S %p',)
11 
12 ch=logging.StreamHandler()
13 
14 ch.setFormatter(form)
15 # ch.setLevel(10)
16 ch.setLevel(20)
17 
18 l1=logging.getLogger('root')
19 # l1.setLevel(20)
20 l1.setLevel(10)
21 l1.addHandler(ch)
22 
23 l1.debug('l1 debug')

  7,应用

  1 """
  2 logging配置
  3 """
  4 
  5 import os
  6 import logging.config
  7 
  8 # 定义三种日志输出格式 开始
  9 
 10 standard_format = '[%(asctime)s][%(threadName)s:%(thread)d][task_id:%(name)s][%(filename)s:%(lineno)d]' \
 11                   '[%(levelname)s][%(message)s]' #其中name为getlogger指定的名字
 12 
 13 simple_format = '[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d]%(message)s'
 14 
 15 id_simple_format = '[%(levelname)s][%(asctime)s] %(message)s'
 16 
 17 # 定义日志输出格式 结束
 18 
 19 logfile_dir = os.path.dirname(os.path.abspath(__file__))  # log文件的目录
 20 
 21 logfile_name = 'all2.log'  # log文件名
 22 
 23 # 如果不存在定义的日志目录就创建一个
 24 if not os.path.isdir(logfile_dir):
 25     os.mkdir(logfile_dir)
 26 
 27 # log文件的全路径
 28 logfile_path = os.path.join(logfile_dir, logfile_name)
 29 
 30 # log配置字典
 31 LOGGING_DIC = {
 32     'version': 1,
 33     'disable_existing_loggers': False,
 34     'formatters': {
 35         'standard': {
 36             'format': standard_format
 37         },
 38         'simple': {
 39             'format': simple_format
 40         },
 41     },
 42     'filters': {},
 43     'handlers': {
 44         #打印到终端的日志
 45         'console': {
 46             'level': 'DEBUG',
 47             'class': 'logging.StreamHandler',  # 打印到屏幕
 48             'formatter': 'simple'
 49         },
 50         #打印到文件的日志,收集info及以上的日志
 51         'default': {
 52             'level': 'DEBUG',
 53             'class': 'logging.handlers.RotatingFileHandler',  # 保存到文件
 54             'formatter': 'standard',
 55             'filename': logfile_path,  # 日志文件
 56             'maxBytes': 1024*1024*5,  # 日志大小 5M
 57             'backupCount': 5,
 58             'encoding': 'utf-8',  # 日志文件的编码,再也不用担心中文log乱码了
 59         },
 60     },
 61     'loggers': {
 62         #logging.getLogger(__name__)拿到的logger配置
 63         '': {
 64             'handlers': ['default', 'console'],  # 这里把上面定义的两个handler都加上,即log数据既写入文件又打印到屏幕
 65             'level': 'DEBUG',
 66             'propagate': True,  # 向上(更高level的logger)传递
 67         },
 68     },
 69 }
 70 
 71 
 72 def load_my_logging_cfg():
 73     logging.config.dictConfig(LOGGING_DIC)  # 导入上面定义的logging配置
 74     logger = logging.getLogger(__name__)  # 生成一个log实例
 75     logger.info('It works!')  # 记录该文件的运行状态
 76 
 77 if __name__ == '__main__':
 78     load_my_logging_cfg()
 79 复制代码
 80 
 81 复制代码
 82 """
 83 MyLogging Test
 84 """
 85 
 86 import time
 87 import logging
 88 import my_logging  # 导入自定义的logging配置
 89 
 90 logger = logging.getLogger(__name__)  # 生成logger实例
 91 
 92 
 93 def demo():
 94     logger.debug("start range... time:{}".format(time.time()))
 95     logger.info("中文测试开始。。。")
 96     for i in range(10):
 97         logger.debug("i:{}".format(i))
 98         time.sleep(0.2)
 99     else:
100         logger.debug("over range... time:{}".format(time.time()))
101     logger.info("中文测试结束。。。")
102 
103 if __name__ == "__main__":
104     my_logging.load_my_logging_cfg()  # 在你程序文件的入口加载自定义logging配置
105     demo()
106 复制代码
107 
108 复制代码
109 注意注意注意:
110 
111 
112 #1、有了上述方式我们的好处是:所有与logging模块有关的配置都写到字典中就可以了,更加清晰,方便管理
113 
114 
115 #2、我们需要解决的问题是:
116     1、从字典加载配置:logging.config.dictConfig(settings.LOGGING_DIC)
117 
118     2、拿到logger对象来产生日志
119     logger对象都是配置到字典的loggers 键对应的子字典中的
120     按照我们对logging模块的理解,要想获取某个东西都是通过名字,也就是key来获取的
121     于是我们要获取不同的logger对象就是
122     logger=logging.getLogger('loggers子字典的key名')
123 
124     
125     但问题是:如果我们想要不同logger名的logger对象都共用一段配置,那么肯定不能在loggers子字典中定义n个key   
126  'loggers': {    
127         'l1': {
128             'handlers': ['default', 'console'],  #
129             'level': 'DEBUG',
130             'propagate': True,  # 向上(更高level的logger)传递
131         },
132         'l2: {
133             'handlers': ['default', 'console' ], 
134             'level': 'DEBUG',
135             'propagate': False,  # 向上(更高level的logger)传递
136         },
137         'l3': {
138             'handlers': ['default', 'console'],  #
139             'level': 'DEBUG',
140             'propagate': True,  # 向上(更高level的logger)传递
141         },
142 
143 }
144 
145     
146 #我们的解决方式是,定义一个空的key
147     'loggers': {
148         '': {
149             'handlers': ['default', 'console'], 
150             'level': 'DEBUG',
151             'propagate': True, 
152         },
153 
154 }
155 
156 这样我们再取logger对象时
157 logging.getLogger(__name__),不同的文件__name__不同,这保证了打印日志时标识信息不同,但是拿着该名字去loggers里找key名时却发现找不到,于是默认使用key=''的配置
158 复制代码
159 另外一个django的配置,瞄一眼就可以,跟上面的一样
160 
161 复制代码
162 #logging_config.py
163 LOGGING = {
164     'version': 1,
165     'disable_existing_loggers': False,
166     'formatters': {
167         'standard': {
168             'format': '[%(asctime)s][%(threadName)s:%(thread)d][task_id:%(name)s][%(filename)s:%(lineno)d]'
169                       '[%(levelname)s][%(message)s]'
170         },
171         'simple': {
172             'format': '[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d]%(message)s'
173         },
174         'collect': {
175             'format': '%(message)s'
176         }
177     },
178     'filters': {
179         'require_debug_true': {
180             '()': 'django.utils.log.RequireDebugTrue',
181         },
182     },
183     'handlers': {
184         #打印到终端的日志
185         'console': {
186             'level': 'DEBUG',
187             'filters': ['require_debug_true'],
188             'class': 'logging.StreamHandler',
189             'formatter': 'simple'
190         },
191         #打印到文件的日志,收集info及以上的日志
192         'default': {
193             'level': 'INFO',
194             'class': 'logging.handlers.RotatingFileHandler',  # 保存到文件,自动切
195             'filename': os.path.join(BASE_LOG_DIR, "xxx_info.log"),  # 日志文件
196             'maxBytes': 1024 * 1024 * 5,  # 日志大小 5M
197             'backupCount': 3,
198             'formatter': 'standard',
199             'encoding': 'utf-8',
200         },
201         #打印到文件的日志:收集错误及以上的日志
202         'error': {
203             'level': 'ERROR',
204             'class': 'logging.handlers.RotatingFileHandler',  # 保存到文件,自动切
205             'filename': os.path.join(BASE_LOG_DIR, "xxx_err.log"),  # 日志文件
206             'maxBytes': 1024 * 1024 * 5,  # 日志大小 5M
207             'backupCount': 5,
208             'formatter': 'standard',
209             'encoding': 'utf-8',
210         },
211         #打印到文件的日志
212         'collect': {
213             'level': 'INFO',
214             'class': 'logging.handlers.RotatingFileHandler',  # 保存到文件,自动切
215             'filename': os.path.join(BASE_LOG_DIR, "xxx_collect.log"),
216             'maxBytes': 1024 * 1024 * 5,  # 日志大小 5M
217             'backupCount': 5,
218             'formatter': 'collect',
219             'encoding': "utf-8"
220         }
221     },
222     'loggers': {
223         #logging.getLogger(__name__)拿到的logger配置
224         '': {
225             'handlers': ['default', 'console', 'error'],
226             'level': 'DEBUG',
227             'propagate': True,
228         },
229         #logging.getLogger('collect')拿到的logger配置
230         'collect': {
231             'handlers': ['console', 'collect'],
232             'level': 'INFO',
233         }
234     },
235 }
236 
237 
238 # -----------
239 # 用法:拿到俩个logger
240 
241 logger = logging.getLogger(__name__) #线上正常的日志
242 collect_logger = logging.getLogger("collect") #领导说,需要为领导们单独定制领导们看的日志

  8,日志配置字典

 1 """
 2 logging配置
 3 """
 4 
 5 import os
 6 
 7 # 1、定义三种日志输出格式,日志中可能用到的格式化串如下
 8 # %(name)s Logger的名字
 9 # %(levelno)s 数字形式的日志级别
10 # %(levelname)s 文本形式的日志级别
11 # %(pathname)s 调用日志输出函数的模块的完整路径名,可能没有
12 # %(filename)s 调用日志输出函数的模块的文件名
13 # %(module)s 调用日志输出函数的模块名
14 # %(funcName)s 调用日志输出函数的函数名
15 # %(lineno)d 调用日志输出函数的语句所在的代码行
16 # %(created)f 当前时间,用UNIX标准的表示时间的浮 点数表示
17 # %(relativeCreated)d 输出日志信息时的,自Logger创建以 来的毫秒数
18 # %(asctime)s 字符串形式的当前时间。默认格式是 “2003-07-08 16:49:45,896”。逗号后面的是毫秒
19 # %(thread)d 线程ID。可能没有
20 # %(threadName)s 线程名。可能没有
21 # %(process)d 进程ID。可能没有
22 # %(message)s用户输出的消息
23 
24 # 2、强调:其中的%(name)s为getlogger时指定的名字
25 standard_format = '[%(asctime)s][%(threadName)s:%(thread)d][task_id:%(name)s][%(filename)s:%(lineno)d]' \
26                   '[%(levelname)s][%(message)s]'
27 
28 simple_format = '[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d]%(message)s'
29 
30 test_format = '%(asctime)s] %(message)s'
31 
32 # 3、日志配置字典
33 LOGGING_DIC = {
34     'version': 1,
35     'disable_existing_loggers': False,
36     'formatters': {
37         'standard': {
38             'format': standard_format
39         },
40         'simple': {
41             'format': simple_format
42         },
43         'test': {
44             'format': test_format
45         },
46     },
47     'filters': {},
48     'handlers': {
49         #打印到终端的日志
50         'console': {
51             'level': 'DEBUG',
52             'class': 'logging.StreamHandler',  # 打印到屏幕
53             'formatter': 'simple'
54         },
55         #打印到文件的日志,收集info及以上的日志
56         'default': {
57             'level': 'DEBUG',
58             'class': 'logging.handlers.RotatingFileHandler',  # 保存到文件,日志轮转
59             'formatter': 'standard',
60             # 可以定制日志文件路径
61             # BASE_DIR = os.path.dirname(os.path.abspath(__file__))  # log文件的目录
62             # LOG_PATH = os.path.join(BASE_DIR,'a1.log')
63             'filename': 'a1.log',  # 日志文件
64             'maxBytes': 1024*1024*5,  # 日志大小 5M
65             'backupCount': 5,
66             'encoding': 'utf-8',  # 日志文件的编码,再也不用担心中文log乱码了
67         },
68         'other': {
69             'level': 'DEBUG',
70             'class': 'logging.FileHandler',  # 保存到文件
71             'formatter': 'test',
72             'filename': 'a2.log',
73             'encoding': 'utf-8',
74         },
75     },
76     'loggers': {
77         #logging.getLogger(__name__)拿到的logger配置
78         '': {
79             'handlers': ['default', 'console'],  # 这里把上面定义的两个handler都加上,即log数据既写入文件又打印到屏幕
80             'level': 'DEBUG', # loggers(第一层日志级别关限制)--->handlers(第二层日志级别关卡限制)
81             'propagate': False,  # 默认为True,向上(更高level的logger)传递,通常设置为False即可,否则会一份日志向上层层传递
82         },
83         '专门的采集': {
84             'handlers': ['other',],
85             'level': 'DEBUG',
86             'propagate': False,
87         },
88     },

  注意:

 1 import settings
 2 
 3 # !!!强调!!!
 4 # 1、logging是一个包,需要使用其下的config、getLogger,可以如下导入
 5 # from logging import config
 6 # from logging import getLogger
 7 
 8 # 2、也可以使用如下导入
 9 import logging.config # 这样连同logging.getLogger都一起导入了,然后使用前缀logging.config.
10 
11 # 3、加载配置
12 logging.config.dictConfig(settings.LOGGING_DIC)
13 
14 # 4、输出日志
15 logger1=logging.getLogger('用户交易')
16 logger1.info('egon儿子alex转账3亿冥币')
17 
18 # logger2=logging.getLogger('专门的采集') # 名字传入的必须是'专门的采集',与LOGGING_DIC中的配置唯一对应
19 # logger2.debug('专门采集的日志')

  日志名字:

      

  日志轮转:

    就是设置日志文件的大小,保证超出文件大小时会创建新的文件。但注意的是会把老的文件放到新创立的文件里,这样就会保证新的日志永远在指定的文件夹里。

 十一,re模块

  

        

 

 

一:什么是正则?

 正则就是用一些具有特殊含义的符号组合到一起(称为正则表达式)来描述字符或者字符串的方法。或者说:正则就是用来描述一类事物的规则。(在Python中)它内嵌在Python中,并通过 re 模块实现。正则表达式模式被编译成一系列的字节码,然后由用 C 编写的匹配引擎执行。

生活中处处都是正则:

    比如我们描述:4条腿

      你可能会想到的是四条腿的动物或者桌子,椅子等

    继续描述:4条腿,活的

          就只剩下四条腿的动物这一类了

二:常用匹配模式(元字符)

http://blog.csdn.net/yufenghyc/article/details/51078107

复制代码
# =================================匹配模式=================================
#一对一的匹配
# 'hello'.replace(old,new)
# 'hello'.find('pattern')

#正则匹配
import re
#\w与\W
print(re.findall('\w','hello egon 123')) #['h', 'e', 'l', 'l', 'o', 'e', 'g', 'o', 'n', '1', '2', '3']
print(re.findall('\W','hello egon 123')) #[' ', ' ']

#\s与\S
print(re.findall('\s','hello  egon  123')) #[' ', ' ', ' ', ' ']
print(re.findall('\S','hello  egon  123')) #['h', 'e', 'l', 'l', 'o', 'e', 'g', 'o', 'n', '1', '2', '3']

#\n \t都是空,都可以被\s匹配
print(re.findall('\s','hello \n egon \t 123')) #[' ', '\n', ' ', ' ', '\t', ' ']

#\n与\t
print(re.findall(r'\n','hello egon \n123')) #['\n']
print(re.findall(r'\t','hello egon\t123')) #['\n']

#\d与\D
print(re.findall('\d','hello egon 123')) #['1', '2', '3']
print(re.findall('\D','hello egon 123')) #['h', 'e', 'l', 'l', 'o', ' ', 'e', 'g', 'o', 'n', ' ']

#\A与\Z
print(re.findall('\Ahe','hello egon 123')) #['he'],\A==>^
print(re.findall('123\Z','hello egon 123')) #['he'],\Z==>$


指定匹配必须出现在字符串的开头或行的开头。

\A 
指定匹配必须出现在字符串的开头(忽略 Multiline 选项)。


指定匹配必须出现在以下位置:字符串结尾、字符串结尾的 \n 之前或行的结尾。

\Z 
指定匹配必须出现在字符串的结尾或字符串结尾的 \n 之前(忽略 Multiline 选项)。

#^与$
print(re.findall('^h','hello egon 123')) #['h']
print(re.findall('3$','hello egon 123')) #['3']

# 重复匹配:| . | * | ? | .* | .*? | + | {n,m} |
#.
print(re.findall('a.b','a1b')) #['a1b']
print(re.findall('a.b','a1b a*b a b aaab')) #['a1b', 'a*b', 'a b', 'aab']
print(re.findall('a.b','a\nb')) #[]
print(re.findall('a.b','a\nb',re.S)) #['a\nb']
print(re.findall('a.b','a\nb',re.DOTALL)) #['a\nb']同上一条意思一样

#*
print(re.findall('ab*','bbbbbbb')) #[]
print(re.findall('ab*','a')) #['a']
print(re.findall('ab*','abbbb')) #['abbbb']

#?
print(re.findall('ab?','a')) #['a']
print(re.findall('ab?','abbb')) #['ab']
#匹配所有包含小数在内的数字
print(re.findall('\d+\.?\d*',"asdfasdf123as1.13dfa12adsf1asdf3")) #['123', '1.13', '12', '1', '3']

#.*默认为贪婪匹配
print(re.findall('a.*b','a1b22222222b')) #['a1b22222222b']

#.*?为非贪婪匹配:推荐使用
print(re.findall('a.*?b','a1b22222222b')) #['a1b']

#+
print(re.findall('ab+','a')) #[]
print(re.findall('ab+','abbb')) #['abbb']

#{n,m}
print(re.findall('ab{2}','abbb')) #['abb']
print(re.findall('ab{2,4}','abbb')) #['abb']
print(re.findall('ab{1,}','abbb')) #'ab{1,}' ===> 'ab+'
print(re.findall('ab{0,}','abbb')) #'ab{0,}' ===> 'ab*'

#[]
print(re.findall('a[1*-]b','a1b a*b a-b')) #[]内的都为普通字符了,且如果-没有被转意的话,应该放到[]的开头或结尾
print(re.findall('a[^1*-]b','a1b a*b a-b a=b')) #[]内的^代表的意思是取反,所以结果为['a=b']
print(re.findall('a[0-9]b','a1b a*b a-b a=b')) #[]内的^代表的意思是取反,所以结果为['a=b']
print(re.findall('a[a-z]b','a1b a*b a-b a=b aeb')) #[]内的^代表的意思是取反,所以结果为['a=b']
print(re.findall('a[a-zA-Z]b','a1b a*b a-b a=b aeb aEb')) #[]内的^代表的意思是取反,所以结果为['a=b']

#\# print(re.findall('a\\c','a\c')) #对于正则来说a\\c确实可以匹配到a\c,但是在python解释器读取a\\c时,会发生转义,然后交给re去执行,所以抛出异常
print(re.findall(r'a\\c','a\c')) #r代表告诉解释器使用rawstring,即原生字符串,把我们正则内的所有符号都当普通字符处理,不要转义
print(re.findall('a\\\\c','a\c')) #同上面的意思一样,和上面的结果一样都是['a\\c']

#():分组
print(re.findall('ab+','ababab123')) #['ab', 'ab', 'ab']
print(re.findall('(ab)+123','ababab123')) #['ab'],匹配到末尾的ab123中的ab
print(re.findall('(?:ab)+123','ababab123')) #findall的结果不是匹配的全部内容,而是组内的内容,?:可以让结果为匹配的全部内容
print(re.findall('href="(.*?)"','<a href="http://www.baidu.com">点击</a>'))#['http://www.baidu.com']
print(re.findall('href="(?:.*?)"','<a href="http://www.baidu.com">点击</a>'))#['href="http://www.baidu.com"']

#|
print(re.findall('compan(?:y|ies)','Too many companies have gone bankrupt, and the next one is my company'))
复制代码

 

复制代码
# ===========================re模块提供的方法介绍===========================
import re
#1
print(re.findall('e','alex make love') )   #['e', 'e', 'e'],返回所有满足匹配条件的结果,放在列表里
#2
print(re.search('e','alex make love').group()) #e,只到找到第一个匹配然后返回一个包含匹配信息的对象,该对象可以通过调用group()方法得到匹配的字符串,如果字符串没有匹配,则返回None。

#3
print(re.match('e','alex make love'))    #None,同search,不过在字符串开始处进行匹配,完全可以用search+^代替match

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

#5
print('===>',re.sub('a','A','alex make love')) #===> Alex mAke love,不指定n,默认替换所有
print('===>',re.sub('a','A','alex make love',1)) #===> Alex make love
print('===>',re.sub('a','A','alex make love',2)) #===> Alex mAke love
print('===>',re.sub('^(\w+)(.*?\s)(\w+)(.*?\s)(\w+)(.*?)$',r'\5\2\3\4\1','alex make love')) #===> love make alex

print('===>',re.subn('a','A','alex make love')) #===> ('Alex mAke love', 2),结果带有总共替换的个数


#6
obj=re.compile('\d{2}')

print(obj.search('abc123eeee').group()) #12
print(obj.findall('abc123eeee')) #['12'],重用了obj
复制代码
 补充一
复制代码
#补充二
import re

#使用|,先匹配的先生效,|左边是匹配小数,而findall最终结果是查看分组,所有即使匹配成功小数也不会存入结果
#而不是小数时,就去匹配(-?\d+),匹配到的自然就是,非小数的数,在此处即整数
#
print(re.findall(r"-?\d+\.\d*|(-?\d+)","1-2*(60+(-40.35/5)-(-4*3))")) #找出所有整数['1', '-2', '60', '', '5', '-4', '3']

#找到所有数字:
print(re.findall('\D?(\-?\d+\.?\d*)',"1-2*(60+(-40.35/5)-(-4*3))")) # ['1','2','60','-40.35','5','-4','3']

#计算器作业参考:http://www.cnblogs.com/wupeiqi/articles/4949995.html
expression='1-2*((60+2*(-3-40.0/5)*(9-2*5/3+7/3*99/4*2998+10*568/14))-(-4*3)/(16-3*2))'

content=re.search('\(([\-\+\*\/]*\d+\.?\d*)+\)',expression).group() #(-3-40.0/5)
复制代码
 search与findall
 View Code

作业:

 View Code

 

补充:

推荐阅读:

https://www.cnblogs.com/linhaifeng/articles/13432794.html

 

正则表达式中(?:pattern)、(?=pattern)、(?!pattern)、(?<=pattern)和(?<!pattern)

下述表达式都是断言,不占用宽度

 

    前面有,正向后发(?<=exp),放前面;

 

    后面有,正向先行(?=exp),放后面;

 

    前面无,反向后发(?<!exp),放前面;

 

    后面无,反向先行(?!exp),放后面。

 例如

 

复制代码
re.findall("egon(?=100|N)(?=N)N123","egonN123")  # ['egonN123']

# 位置:   0    1    2    3    4    5    6     7
# 字符串:e    g    o    n    N    1    2    3


# 分析:
# 步骤1、正则表达式egon匹配到了字符串的位置3

然后连续进行两次断言匹配
# 步骤2、(?=100|N)从位置3作为起始匹配位置4的字符是否100或者N
# 步骤3、2成功后,继续匹配(?=N),因为?=patter不会吃字符,所以此时会重新回到步骤1所在位置3,然后继续匹配,匹配成功

# 步骤4、从位置3开始匹配N123


# 思考下述输出结果,为何会不同???:
re.findall("egon(?=100|N)(?=N)N123","egonN123")
re.findall("egon(?=100|N)(?=N)123","egonN123")
复制代码

 

 

 

介绍

 

 

 

 

(pattern) : 匹配 pattern 并获取这一匹配,所获取的匹配可以从产生的 Matches 集合得到。
(?:pattern) :匹配 pattern 但不获取匹配结果,也就是说这是一个非获取匹配,不进行存储供以后使用。
(?=pattern) :正向预查,在任何匹配 pattern 的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始。

 

共同点

 

(?:pattern) 与 (?=pattern)都匹配pattern,但不会把pattern结果放到Matches的集合中,即Matcher.group()不会匹配到(?;pattern)与(?=pattern)

 

区别

 

    • (?:pattern) 匹配得到的结果包含pattern,(?=pattern) 则不包含。如:
      对字符串:"industry abc"的匹配结果:
      industr(?:y|ies) ---> "industry"
      industr(?=y|ies) ---> "industr"

      是否消耗字符
      (?:pattern) 消耗字符,下一字符匹配会从已匹配后的位置开始。
      (?=pattern) 不消耗字符,下一字符匹配会从预查之前的位置开始。
      即后者只预查,不移动匹配指针。如:

 

 

 

posted on 2024-02-14 02:46  我才是最帅的那个男人  阅读(21)  评论(0)    收藏  举报

导航