re模块
一:什么是正则?
正则就是用一些具有特殊含义的符号组合到一起(称为正则表达式)来描述字符或者字符串的方法。或者说:正则就是用来描述一类事物的规则。(在Python中)它内嵌在Python中,并通过 re 模块实现。正则表达式模式被编译成一系列的字节码,然后由用 C 编写的匹配引擎执行。
生活中处处都是正则:
比如我们描述:4条腿
你可能会想到的是四条腿的动物或者桌子,椅子等
继续描述:4条腿,活的
就只剩下四条腿的动物这一类了
二:常用匹配模式(元字符)
# =================================匹配模式================================= #一对一的匹配 # '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'] # 都是空,都可以被s匹配 print(re.findall('s','hello egon 123')) #[' ', ' ', ' ', ' ', ' ', ' '] # 与 print(re.findall(r' ','hello egon 123')) #[' '] print(re.findall(r' ','hello egon 123')) #[' '] #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与 print(re.findall('Ahe','hello egon 123')) #['he'],A==>^ print(re.findall('123','hello egon 123')) #['he'],==>$ #^与$ 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 b')) #[] print(re.findall('a.b','a b',re.S)) #['a b'] print(re.findall('a.b','a b',re.DOTALL)) #['a b']同上一条意思一样 #* 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','ac')) #对于正则来说a\c确实可以匹配到ac,但是在python解释器读取a\c时,会发生转义,然后交给re去执行,所以抛出异常 print(re.findall(r'a\c','ac')) #r代表告诉解释器使用rawstring,即原生字符串,把我们正则内的所有符号都当普通字符处理,不要转义 print(re.findall('a\\c','ac')) #同上面的意思一样,和上面的结果一样都是['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'))
mport re # print(re.findall('w','ab 12+- *&_')) # w # print(re.findall('W','ab 12+- *&_')) # print(re.findall('s','ab 1 2 +- *&_')) # print(re.findall('S','ab 1 2 +- *&_')) # print(re.findall('d','ab 1 2 +- *&_')) # d # print(re.findall('D','ab 1 2 +- *&_')) # print(re.findall('w_sb','egon alex_sb123123wxx_sb,lxx_sb')) # w_sb # print(re.findall('Aalex','abcalex is salexb')) # print(re.findall('Aalex','alex is salexb')) # print(re.findall('^alex','alex is salexb')) # print(re.findall('sb','alexsb is sbalexbsb')) # print(re.findall('sb$','alexsb is sbalexbsb')) # sb # print(re.findall('^ebn$','ebn1')) # ebn # print(re.findall('a c','a c a c a1c')) # 重复匹配: #. ? * + {m,n} .* .*? #1、.:代表除了换行符外的任意一个字符 # print(re.findall('a.c','abc a1c aAc aaaaaca c')) # a.c # print(re.findall('a.c','abc a1c aAc aaaaaca c',re.DOTALL)) #2、?:代表左边那一个字符重复0次或1次 # print(re.findall('ab?','a ab abb abbb abbbb abbbb')) # ab? #3、*:代表左边那一个字符出现0次或无穷次 # print(re.findall('ab*','a ab abb abbb abbbb abbbb a1bbbbbbb')) # ab* #4、+ :代表左边那一个字符出现1次或无穷次 # print(re.findall('ab+','a ab abb abbb abbbb abbbb a1bbbbbbb')) # ab+ #5、{m,n}:代表左边那一个字符出现m次到n次 # print(re.findall('ab?','a ab abb abbb abbbb abbbb')) # print(re.findall('ab{0,1}','a ab abb abbb abbbb abbbb')) # print(re.findall('ab*','a ab abb abbb abbbb abbbb a1bbbbbbb')) # print(re.findall('ab{0,}','a ab abb abbb abbbb abbbb a1bbbbbbb')) # print(re.findall('ab+','a ab abb abbb abbbb abbbb a1bbbbbbb')) # print(re.findall('ab{1,}','a ab abb abbb abbbb abbbb a1bbbbbbb')) # print(re.findall('ab{1,3}','a ab abb abbb abbbb abbbb a1bbbbbbb')) #6、.*:匹配任意长度,任意的字符=====》贪婪匹配 # print(re.findall('a.*c','ac a123c aaaac a *123)()c asdfasfdsadf')) # a.*c #7、.*?:非贪婪匹配 # print(re.findall('a.*?c','a123c456c')) # ():分组 # print(re.findall('(alex)_sb','alex_sb asdfsafdafdaalex_sb')) # (alex)_sb # print(re.findall( # 'href="(.*?)"', # '<li><a id="blog_nav_sitehome" class="menu" href="http://www.cnblogs.com/">博客园</a></li>') # ) # <li><a id="blog_nav_sitehome" class="menu" href="http://www.cnblogs.com/">博客园</a></li> # href=".*?" # []:匹配一个指定范围内的字符(这一个字符来自于括号内定义的) # print(re.findall('a[0-9][0-9]c','a1c a+c a2c a9c a11c a-c acc aAc')) #当-需要被当中普通符号匹配时,只能放到[]的最左边或最 右边 # print(re.findall('a[-+*]c','a1c a+c a2c a9c a*c a11c a-c acc aAc')) # print(re.findall('a[a-zA-Z]c','a1c a+c a2c a9c a*c a11c a-c acc aAc')) # []内的^代表取反的意思 # print(re.findall('a[^a-zA-Z]c','a c a1c a+c a2c a9c a*c a11c a-c acc aAc')) # print(re.findall('a[^0-9]c','a c a1c a+c a2c a9c a*c a11c a-c acc aAc')) # print(re.findall('([a-z]+)_sb','egon alex_sb123123wxxxxxxxxxxxxx_sb,lxx_sb')) # [a-z]+_sb # | :或者 # print(re.findall('compan(ies|y)','Too many companies have gone bankrupt, and the next one is my company')) # (?:):代表取匹配成功的所有内容,而不仅仅只是括号内的内容 # print(re.findall('compan(?:ies|y)','Too many companies have gone bankrupt, and the next one is my company')) # print(re.findall('alex|sb','alex sb sadfsadfasdfegon alex sb egon')) # re模块的其他方法: # print(re.findall('alex|sb','123123 alex sb sadfsadfasdfegon alex sb egon')) # print(re.search('alex|sb','123213 alex sb sadfsadfasdfegon alex sb egon').group()) # print(re.search('^alex','123213 alex sb sadfsadfasdfegon alex sb egon')) # print(re.search('^alex','alex sb sadfsadfasdfegon alex sb egon').group()) # print(re.match('alex','alex sb sadfsadfasdfegon alex sb egon').group()) # print(re.match('alex','123213 alex sb sadfsadfasdfegon alex sb egon')) # info='a:b:c:d' # print(info.split(':')) # print(re.split(':',info)) # info=r'get :a.txt3333/rwx' # print(re.split('[ :\/]',info)) # print('egon is beutifull egon'.replace('egon','EGON',1)) # print(re.sub('(.*?)(egon)(.*?)(egon)(.*?)',r'123EGON5','123 egon is beutifull egon 123')) # (123 )(egon)( is beutifull )(egon)( 123) #123EGON5 # print(re.sub('(lqz)(.*?)(SB)',r'321',r'lqz is SB')) # print(re.sub('([a-zA-Z]+)([^a-zA-Z]+)([a-zA-Z]+)([^a-zA-Z]+)([a-zA-Z]+)',r'52341',r'lqzzzz123+ is SB')) #(lqzzzz)(123+ )(is)( )(SB) pattern=re.compile('alex') print(pattern.findall('alex is alex alex')) print(pattern.findall('alexasdfsadfsadfasdfasdfasfd is alex alex'))
#为何同样的表达式search与findall却有不同结果: print(re.search('(([+-*/]*d+.?d*)+)',"1-12*(60+(-40.35/5)-(-4*3))").group()) #(-40.35/5) print(re.findall('(([+-*/]*d+.?d*)+)',"1-12*(60+(-40.35/5)-(-4*3))")) #['/5', '*3'] #看这个例子:(d)+相当于(d)(d)(d)(d)...,是一系列分组 print(re.search('(d)+','123').group()) #group的作用是将所有组拼接到一起显示出来
#_*_coding:utf-8_*_ __author__ = 'Linhaifeng' #在线调试工具:tool.oschina.net/regex/# import re s=''' http://www.baidu.com egon@oldboyedu.com 你好 010-3141 ''' #最常规匹配 # content='Hello 123 456 World_This is a Regex Demo' # res=re.match('Hellosdddsd{3}sw{10}.*Demo',content) # print(res) # print(res.group()) # print(res.span()) #泛匹配 # content='Hello 123 456 World_This is a Regex Demo' # res=re.match('^Hello.*Demo',content) # print(res.group()) #匹配目标,获得指定数据 # content='Hello 123 456 World_This is a Regex Demo' # res=re.match('^Hellos(d+)s(d+)s.*Demo',content) # print(res.group()) #取所有匹配的内容 # print(res.group(1)) #取匹配的第一个括号内的内容 # print(res.group(2)) #去陪陪的第二个括号内的内容 #贪婪匹配:.*代表匹配尽可能多的字符 # import re # content='Hello 123 456 World_This is a Regex Demo' # # res=re.match('^He.*(d+).*Demo$',content) # print(res.group(1)) #只打印6,因为.*会尽可能多的匹配,然后后面跟至少一个数字 #非贪婪匹配:?匹配尽可能少的字符 # import re # content='Hello 123 456 World_This is a Regex Demo' # # res=re.match('^He.*?(d+).*Demo$',content) # print(res.group(1)) #只打印6,因为.*会尽可能多的匹配,然后后面跟至少一个数字 #匹配模式:.不能匹配换行符 content='''Hello 123456 World_This is a Regex Demo ''' # res=re.match('He.*?(d+).*?Demo$',content) # print(res) #输出None # res=re.match('He.*?(d+).*?Demo$',content,re.S) #re.S让.可以匹配换行符 # print(res) # print(res.group(1)) #转义: # content='price is $5.00' # res=re.match('price is $5.00',content) # print(res) # # res=re.match('price is $5.00',content) # print(res) #总结:尽量精简,详细的如下 # 尽量使用泛匹配模式.* # 尽量使用非贪婪模式:.*? # 使用括号得到匹配目标:用group(n)去取得结果 # 有换行符就用re.S:修改模式 #re.search:会扫描整个字符串,不会从头开始,找到第一个匹配的结果就会返回 # import re # content='Extra strings Hello 123 456 World_This is a Regex Demo Extra strings' # # res=re.match('Hello.*?(d+).*?Demo',content) # print(res) #输出结果为None # # import re # content='Extra strings Hello 123 456 World_This is a Regex Demo Extra strings' # # res=re.search('Hello.*?(d+).*?Demo',content) # # print(res.group(1)) #输出结果为 #re.search:只要一个结果,匹配演练, import re content=''' <tbody> <tr id="4766303201494371851675" class="even "><td><div class="hd"><span class="num">1</span><div class="rk "><span class="u-icn u-icn-75"></span></div></div></td><td class="rank"><div class="f-cb"><div class="tt"><a href="/song?id=476630320"><img class="rpic" src="http://p1.music.126.net/Wl7T1LBRhZFg0O26nnR2iQ==/19217264230385030.jpg?param=50y50&quality=100"></a><span data-res-id="476630320" " # res=re.search('<ashref=.*?<bstitle="(.*?)".*?b>',content) # print(res.group(1)) #re.findall:找到符合条件的所有结果 # res=re.findall('<ashref=.*?<bstitle="(.*?)".*?b>',content) # for i in res: # print(i) #re.sub:字符串替换 import re content='Extra strings Hello 123 456 World_This is a Regex Demo Extra strings' # content=re.sub('d+','',content) # print(content) #用1取得第一个括号的内容 #用法:将123与456换位置 # import re # content='Extra strings Hello 123 456 World_This is a Regex Demo Extra strings' # # # content=re.sub('(Extra.*?)(d+)(s)(d+)(.*?strings)',r'14325',content) # content=re.sub('(d+)(s)(d+)',r'321',content) # print(content) # import re # content='Extra strings Hello 123 456 World_This is a Regex Demo Extra strings' # # res=re.search('Extra.*?(d+).*strings',content) # print(res.group(1)) # import requests,re # respone=requests.get('https://book.douban.com/').text # print(respone) # print('======'*1000) # print('======'*1000) # print('======'*1000) # print('======'*1000) # res=re.findall('<li.*?cover.*?href="(.*?)".*?title="(.*?)">.*?more-meta.*?author">(.*?)</span.*?year">(.*?)</span.*?publisher">(.*?)</span.*?</li>',respone,re.S) # # res=re.findall('<li.*?cover.*?href="(.*?)".*?more-meta.*?author">(.*?)</span.*?year">(.*?)</span.*?publisher">(.*?)</span>.*?</li>',respone,re.S) # # # for i in res: # print('%s %s %s %s' %(i[0].strip(),i[1].strip(),i[2].strip(),i[3].strip()))
shelve模块
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模块
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数据
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')
configparser模块
# 注释1 ; 注释2 [section1] k1 = v1 k2:v2 user=egon age=18 is_admin=true salary=31 [section2] k1 = v1
import configparser config=configparser.ConfigParser() config.read('a.cfg') #查看所有的标题 res=config.sections() #['section1', 'section2'] print(res) #查看标题section1下所有key=value的key options=config.options('section1') print(options) #['k1', 'k2', 'user', 'age', 'is_admin', 'salary'] #查看标题section1下所有key=value的(key,value)格式 item_list=config.items('section1') print(item_list) #[('k1', 'v1'), ('k2', 'v2'), ('user', 'egon'), ('age', '18'), ('is_admin', 'true'), ('salary', '31')] #查看标题section1下user的值=>字符串格式 val=config.get('section1','user') print(val) #egon #查看标题section1下age的值=>整数格式 val1=config.getint('section1','age') print(val1) #18 #查看标题section1下is_admin的值=>布尔值格式 val2=config.getboolean('section1','is_admin') print(val2) #True #查看标题section1下salary的值=>浮点型格式 val3=config.getfloat('section1','salary') print(val3) #31.0
import configparser config=configparser.ConfigParser() config.read('a.cfg',encoding='utf-8') #删除整个标题section2 config.remove_section('section2') #删除标题section1下的某个k1和k2 config.remove_option('section1','k1') config.remove_option('section1','k2') #判断是否存在某个标题 print(config.has_section('section1')) #判断标题section1下是否有user print(config.has_option('section1','')) #添加一个标题 config.add_section('egon') #在标题egon下添加name=egon,age=18的配置 config.set('egon','name','egon') config.set('egon','age',18) #报错,必须是字符串 #最后将修改的内容写入文件,完成最终的修改 config.write(open('a.cfg','w'))