isscollege 2018-04-28 22:56:58
24189
收藏 42分类专栏: python 正则分组版权
教你用代码玩转PPT相信每个程序猿对写PPT感到困扰,没有灵感,憋得头痛,有了内容,格式又调得心痛,写代码时的灵光乍现,洋洋洒洒都没有了,本课程就是为了解决程序猿写PPT的问题,带领大家使用VS Code+MarkDown语法一步一步写出具有极客范的PPT,本课程还教你使用简单的CSS前端知识去定制PPT主题,批量编写你的超炫PPT。
isscollege
¥9.90订阅博主python3正则表达式的几个高级用法一、 概述本文举例说明python3正则表达式的一些高级级法,主要是各类分组,可应用于1、复杂网页文件中的有用数据例如,采用爬虫技术取得网页后,对网页内任何数据进行提取分析2、 各类配置文件可能是属性文件,读取属性文件中的键值对可能是数据库各类查询的复杂匹配的参数解析,类似mybatis的动态sql语句解析,hibernate动态参数sql分析二、 理解正则表达式的贪婪与非贪婪1、 生活中的贪婪与非贪婪例如公司员工餐厅发小西红柿,每人一次可以领取1—10个如果有的人每次都领取10个,则这个人属于贪婪,就是在不犯错时,每次取最多如果有的人每次都领取1个,则这个人属于不贪婪,就是在不犯错时,每次取最少2、 正则表达式的贪婪与非贪婪定义只有前面的字符串内容可多可少时,才存在贪婪与非贪婪1) 贪婪语法.*,取尽可能多的任意字符\w+,取尽可能多的任意英文字母与数字一次以上\d{2,5},尽可能取到2--5个数字字母\s+,},尽可能取到任意多个空格一次以上.?,任意字符取0次,或1次,尽可能取1次2) 非贪婪语法就是在贪婪定义后面加一个?.*?,取尽可能少的任意字符,尽可能不取\w+?,取尽可能少的任意英文字母与数字,尽可能只取1个\d{2,5},尽可能少数字字母,尽可能只取2个\s+,},尽可能取到最少空格,尽可能只取1个空格.??,任意字符取0次,或1次,尽可能取0次3) 贪婪与贪婪的最终匹配无论贪婪,还是非贪婪,都要与后面内容继续匹配,才能最终确定本次匹配内容,有时给合后面匹配内容时,两都取值相同123456789103、 示例分析如下python语法如下import re匹配到的结果列表=re.findall(r’正则字符串’,要匹配的字符串,re.I|re.S)re.I,表示忽略大小写re.S,表示忽略回行,所有字符包括回行字符字符串贪婪正则非贪婪正则www.baidu.com/num正则:www\.baidu\.com\/.*则能匹配到www.baidu.com/num有num正则www\.baidu\.com\/.*?则能匹配到www.baidu.com/无numwww.baidu.com/num/456www\.baidu\.com\/.*\/\d+则能匹配到www.baidu.com/num/456www\.baidu\.com\/.*?\/\d+则能匹配到www.baidu.com/num/456此时与贪婪正则匹配相同一段网页文本,希望能求出每个div的innerHTML<div>….</div><div>….</div><div>….</div><div>….</div>正则<div>.*</div>则不能匹配出每个<div>标签之间的文本innerText正则<div>.*?</div>则能匹配出每个<div>标签之间的文本innerText4、示例代码如下import res1=re.findall(r'\D+\d+','abc123456') #结果为:['abc123456']s2=re.findall(r'\D+\d+?','abc123456') #结果为:['abc1']s2=re.findall(r'\D+\d*','abc123456') #结果为:['abc123456']s2=re.findall(r'\D+\d*?','abc123456') #结果为:['abc']s2=re.findall(r'\D+\d{2,4}','abc123456') #结果为:['abc1234']s2=re.findall(r'\D+\d{2,4}?','abc123456',re.I) #结果为:['abc12']s2=re.findall(r'\D+\d?','abc123456',re.I) #结果为:['abc1']s2=re.findall(r'\D+\d??','abc123456',re.I) #结果为:['abc']123456789三、 正则表达式的自定义命名分组,(?P)1、 语法说明一个正则表达式可以有多个自定义名称的分组,可以能过分组名称提取到匹配的字符串每一个分组定义是(?P<自定义分组名称>正则字符串)例如pattern=r’正则1(?P<组1>组1正则)正则2(?P<组2>组2正则)正则3(?P<组3>组3正则)’2、 需求如下这是一段java代码字符串,有下面几种分析需求1) 需求1,求3个参数,,,,3组实现a) 每个变量的数据类型类型名称前后有数量不相同的空格b) 每个变量名称变量名称前有数量不相同的空格,后面有等号,等号前后有数量不相同的空格c) 每个变量的值值的前后有数量不相同的空格变量最后一定有分号2) 需求2,求2个参数, ,,2组实现a) 每个变量名称要清除变量前后空格b) 每个变量的值要清除值前后空格3) 需求3,求1个参数,,1组实现每个变量的值要清除值前后空格4) 需求4,求1个参数,,1组实现每个变量名称要清除变量名称前后空格3、 示例代码str='''String s1="学习java";String s2= " ";Float 价格=24000.89;String desc = "用于找工作技能提升。。。" ;Integer num = 12567 ;'''import re#需求1,,分3组:<type>,<name>,<value>,求数据类型,变量名称,变量的值,下面3种求法,结果相同s1=re.findall(r'(?=String|Float|Integer)(?P<type>\w+)\s+(?P<name>.*?)\s*?=\s*?(?P<value>.*?)\s*?;',str,re.I|re.S); #结果是:[('String', 's1', '"学习java"'), ('String', 's2', ' " "'), ('Float', '价格', '24000.89'), ('String', 'desc', ' "用于找工作技能提升。。。"'), ('Integer', 'num', ' 12567')]s1=re.findall(r'(?P<type>String|Float|Integer\s+?\w+)\s+(?P<name>.*?)\s*?=\s*?(?P<value>["\d].*?)\s*?;',str,re.I|re.S); #结果是:[('String', 's1', '"学习java"'), ('String', 's2', ' " "'), ('Float', '价格', '24000.89'), ('String', 'desc', ' "用于找工作技能提升。。。"'), ('Integer', 'num', ' 12567')]#优化上面,当变量前面有空格时,要清除["\d],表示双引号或数字开头,匹配结果自动加入到<value>组,正则语法为:不消耗前缀s1=re.findall(r'(?=String|Float|Integer)(?P<type>\w+)\s+(?P<name>.*?)\s*?=\s*?(?=["\d])(?P<value>.*?)\s*?;',str,re.I|re.S); #结果是:[('String', 's1', '"学习java"'), ('String', 's2', '" "'), ('Float', '价格', '24000.89'), ('String', 'desc', '"用于找工作技能提升。。。"'), ('Integer', 'num', '12567')]#需求2,分2组:<name>,<value>,求变量名称,变量的值,s1=re.findall(r'\s+?(?P<name>\S+?)\s*?=\s*?(?P<value>["\d].*?)\s*?;',str,re.I|re.S); #结果是:[('s1', '"学习java"'), ('s2', '" "'), ('价格', '24000.89'), ('desc', '"用于找工作技能提升。。。"'), ('num', '12567')]#需求3,分1组<value>,求每个变量的值,要清除首尾空格,给出2种求法s1=re.findall( r'=\s*?(?P<value>[\d"].*?)\s*?;',str,re.I|re.S); #结果是:['"学习java"', '" "', '24000.89', '"用于找工作技能提升。。。"', '12567']s1=re.findall( r'=\s*?(?=[\d"])(?P<value>.*?)\s*?;',str,re.I|re.S); #结果是:['"学习java"', '" "', '24000.89', '"用于找工作技能提升。。。"', '12567']#需求4,分1个<name>只取变量名称s1=re.findall(r'.*?\s+(?P<name>\w+?)\s*?=.*?;',str,re.I|re.S); #结果是:['s1', 's2', '价格', 'desc', 'num']12345678910111213141516171819202122232425262728四、 应用扩展可以采用类似的方法,对任意复杂业务的sql语句进行配置分析,可能有任意多个字段条件操作,每个字段的值可能有或无,或在某一个范围,这样结合前台提交,后台用正则分组,可以提取任意复杂的sql条件查询,适用于hibernate的动态查询,及springjdbc自定义sql1、 实现需求当一个分组内容,重复出现2次或以上时,第2次起,可以引用前面定义的分组匹配,即r’(P?pattern1)…(P?pattern2)…(P?pattern2)…(?P=name1)…(P=name2)…(?P=name3)’即(?P=name1)重复匹配前面定义的(?Ppattern1),(?P=name2)重复匹配前面定义的(?Ppattern2)2、 示例如下import re#假设下面的每门课的学费,例如oracle:500元,java:1550元str=''' oracle:500, java:1550, bigdata:2000, php:500 <oracle>500</oracle> <java>1550</java> <bigdata>2000</bigdata> <php>500</php> '''#下面2行代码结果相同s1=re.findall(r'oracle:(?P<name1>\d+),.*?java:(?P<name2>\d+),.*?bigdata:(?P<name3>\d+),.*?php:(?P<name4>\d+).*?<oracle>(?P=name1)</oracle>.*?<java>(?P=name2)</java>.*?<bigdata>(?P=name3)</bigdata>.*?<php>(?P=name4)</php>.*?',str,re.I|re.S) #结果是:['500', '1800', '2000', '555']s1=re.findall(r'oracle:(?P<name1>\d+),.*?java:(?P<name2>\d+),.*?bigdata:(?P<name3>\d+),.*?<oracle>(?P=name1)</oracle>.*?<java>(?P=name2)</java>.*?',str,re.I|re.S) #结果是:['500', '1800', '2000', '555']12345678910111213141516171819五、 数字分组,\number1、 语法说明每一段正则用一个加圆括起来时,便自动构成一个组,包括(?Ppattern)自定义命名组,也加入到分组序号中如果后面有前面圆括中相同部分,则用数字序号表示匹配相同部分r’(正则1)…(正则2)…(正则3) 。。。\1….\2….\3…’,这里出现\1,表示匹配前面第1个圆括号正则内容,这里出现\2,表示匹配前面第2个圆括号正则内容2、 可以用数组分组取得自定义命名分组例如用:\2 取得前面第2个圆括号(?Ppattern123)的内容3、 示例如下import re#假设下面的每门课的学费,例如oracle:500元,java:1550元,bigdata:2000元,php:500元str=''' oracle:500, java:1550, bigdata:2000, php:500 <oracle>500</oracle> <java>1550</java> <bigdata>2000</bigdata> <php>500</php> '''#下面需求求所有每门课的学费,只求具体数字,体会(?P<name>)用法,下面2行代码结果相同s1=re.findall(r'\D+:(?P<name>\d+),??',str,re.I|re.S) #结果是:['500', '1550', '2000', '500']s1=re.findall(r'(\w+):(?P<name1>\d+),.*?(\w+):(?P<name2>\d+),.*?(\w+):(?P<name3>\d+),.*?(\w+):(?P<name4>\d+).*?',str,re.I|re.S) #结果是:[('oracle', '500', 'java', '1550', 'bigdata', '2000', 'php', '500')]#下面需求,求出课程名称,及费用,4门课s1=re.findall(r'.*?(\w+):(?P<name1>\d+),.*?(\w+):(?P<name2>\d+),.*?(\w+):(?P<name3>\d+),.*?(\w+):(?P<name4>\d+).*?',str,re.I|re.S) #结果是:[('oracle', '500', 'java', '1550', 'bigdata', '2000', 'php', '500')]#下面3行代码结果相同,括号的序号从1开始,(?P<name>...)也算一个括号s1=re.findall(r'(\w+):(?P<name1>\d+),.*?(\w+):(?P<name2>\d+),.*?<\1>(?P=name1)</\1>.*?<\3>(?P=name2)</\3>.*?',str,re.I|re.S) #结果是:[('oracle', '500', 'java', '1550')]s1=re.findall(r'(\w+):(?P<name1>\d+),.*?(\w+):(?P<name2>\d+),.*?<\1>\2</\1>.*?<\3>(?P=name2)</\3>.*?',str,re.I|re.S) #结果是:[('oracle', '500', 'java', '1550')]s1=re.findall(r'(\w+):(?P<name1>\d+),.*?(\w+):(?P<name2>\d+),.*?<\1>\2</\1>.*?<\3>\4</\3>.*?',str,re.I|re.S) #结果是:[('oracle', '500', 'java', '1550')]#下面2行结果相同s1=re.findall(r'.*?(\w+):(?P<name1>\d+),.*?(\w+):(?P<name2>\d+),.*?(\w+):(?P<name3>\d+),.*?(\w+):(?P<name4>\d+).*?<\1>\2</\1>.*?',str,re.I|re.S) #结果是:[('oracle', '500', 'java', '1550', 'bigdata', '2000', 'php', '500')]s1=re.findall(r'.*?(\w+):(?P<name1>\d+),.*?(\w+):(?P<name2>\d+),.*?(\w+):(?P<name3>\d+),.*?(\w+):(?P<name4>\d+).*?<\1>(?P=name1)</\1>.*?',str,re.I|re.S) #结果是:[('oracle', '500', 'java', '1550', 'bigdata', '2000', 'php', '500')]#下面2行结果相同s1=re.findall(r'.*?(\w+):(?P<name1>\d+),.*?(\w+):(?P<name2>\d+),.*?(\w+):(?P<name3>\d+),.*?(\w+):(?P<name4>\d+).*?<\1>(?P=name1)</\1>.*?<\3>\4</\3>.*?',str,re.I|re.S) #结果是:[('oracle', '500', 'java', '1550', 'bigdata', '2000', 'php', '500')]s1=re.findall(r'.*?(\w+):(?P<name1>\d+),.*?(\w+):(?P<name2>\d+),.*?(\w+):(?P<name3>\d+),.*?(\w+):(?P<name4>\d+).*?<\1>(?P=name1)</\1>.*?<\3>(?P=name2)</\3>.*?',str,re.I|re.S) #结果是:[('oracle', '500', 'java', '1550', 'bigdata', '2000', 'php', '500')]#下面2行结果相同s1=re.findall(r'.*?(\w+):(?P<name1>\d+),.*?(\w+):(?P<name2>\d+),.*?(\w+):(?P<name3>\d+),.*?(\w+):(?P<name4>\d+).*?<\1>(?P=name1)</\1>.*?<\3>(?P=name2)</\3>.*?<\5>\6</\5>.*?',str,re.I|re.S) #结果是:[('oracle', '500', 'java', '1550', 'bigdata', '2000', 'php', '500')]s1=re.findall(r'.*?(\w+):(?P<name1>\d+),.*?(\w+):(?P<name2>\d+),.*?(\w+):(?P<name3>\d+),.*?(\w+):(?P<name4>\d+).*?<\1>(?P=name1)</\1>.*?<\3>(?P=name2)</\3>.*?<\5>(?P=name3)</\5>.*?',str,re.I|re.S) #结果是:[('oracle', '500', 'java', '1550', 'bigdata', '2000', 'php', '500')]#下面2行结果相同s1=re.findall(r'.*?(\w+):(?P<name1>\d+),.*?(\w+):(?P<name2>\d+),.*?(\w+):(?P<name3>\d+),.*?(\w+):(?P<name4>\d+).*?<\1>(?P=name1)</\1>.*?<\3>(?P=name2)</\3>.*?<\5>\6</\5>.*?<\7>\8</\77>.*?',str,re.I|re.S) #结果是:[('oracle', '500', 'java', '1550', 'bigdata', '2000', 'php', '500')]s1=re.findall(r'.*?(\w+):(?P<name1>\d+),.*?(\w+):(?P<name2>\d+),.*?(\w+):(?P<name3>\d+),.*?(\w+):(?P<name4>\d+).*?<\1>(?P=name1)</\1>.*?<\3>(?P=name2)</\3>.*?<\5>\6</\5>.*?<\7>(?P=name4)</\7>.*?',str,re.I|re.S) #结果是:[('oracle', '500', 'java', '1550', 'bigdata', '2000', 'php', '500')]s1=re.findall(r'(\D+):(?P<name1>\d+),.*?(\D+):(?P<name2>\d+),.*?(\D+):(?P<name3>\d+),.*?(\D+):(?P<name4>\d+),.*?<\1>(?P=name1)<\1>.*?',str,re.I|re.S) #结果是:['500', '1800', '2000', '555']#下面s1=re.findall(r'oracle:(?P<name1>\d+),.*?java:(?P<name2>\d+),.*?bigdata:(?P<name3>\d+),.*?php:(?P<name4>\d+).*?<oracle>(?P=name1)</oracle>.*?<java>(?P=name2)</java>.*?<bigdata>(?P=name3)</bigdata>.*?<php>(?P=name4)</php>.*?',str,re.I|re.S) #结果是:['500', '1800', '2000', '555']s1=re.findall(r'oracle:(?P<name1>\d+),.*?java:(?P<name2>\d+),.*?bigdata:(?P<name3>\d+),.*?<oracle>(?P=name1)</oracle>.*?<java>(?P=name2)</java>.*?',str,re.I|re.S) #结果是:['500', '1800', '2000', '555']12345678910111213141516171819202122232425262728293031323334353637383940414243444546六、 前置肯定分组,(?=pattern)1、 实现需求表示以。。。开头,不消耗匹配内容,而是加入后面正则表达式中,所以也称为前置不消耗分组r’…(?=pattern1)(?Ppattern123)…’等效于r’… (?Ppattern1pattern123)…’2、 示例如下#前置肯定(?=pattern)import re#查询url是否以http://www.开头s1=re.findall(r'(?=http:\/\/www\.)(?P<name>.*)','http://www.baidu.com') #结果是:['http://www.baidu.com']s1=re.findall(r'(?=http:\/\/www\.)(?P<name>.*)','https://www.baidu.com') #结果是:[]12345678910七、 前置否定分组,(?!pattern)1、 实现需求表示不包含。。。开头的其余部分,r’…(!pattern1)(?Ppattern123)…’等效于r’… (?P!pattern1pattern123)…’,pattern1的内容只是一个最小正则内容2、 示例如下#前置否定(?!pattern)import re#查询url不包含http://开头以外的其余部分s1=re.findall(r'(?!http:\/\/)(?P<name>www.*)','http://www.baidu.com') #结果是:['www.baidu.com']#查询所有非数字部分,即前面不包含数字,后面是字母s1=re.findall(r'(?!\d+)(?P<name>\D+)','123java456oracle367bigdata478') #结果是:['java', 'oracle', 'bigdata']123456789101112八、 后置肯定分组,(?<=pattern)1、 实现需求表示包含以。。。结尾的所有部分,不消耗匹配内容,而是加入前面分组中r’… (?Ppattern123)(?<=pattern1)…’等效于r’… (?Ppattern123pattern1)…’2、 示例如下#后置肯定(?<=pattern)#下面匹配前面是数字一组,后面包含数字结尾的所有分组import re s=re.findall(r'(?P<name>\d+)(?<=\d)','987java678abc891abe2345stu2454dy')#结果是:['987', '678', '891', '2345', '2454']#下面匹配前面是字母一组,后面包含字母的所有分组 s=re.findall(r'(?P<name>\D+)(?<=\D)','java678abc891abe2345stu2454dy')#结果是:['java', 'abc', 'abe', 'stu', 'dy']12345678九、 后置否定分组,(?#后置否定(?<=pattern)#下面匹配前面是数字一组,后面不包含字母的所有分组 s=re.findall(r'(?P<name>\d+)(?<!\D)','987java678abc891abe2345stu2454dy')#结果是:['987', '678', '891', '2345', '2454']#下面匹配前面是字母一组,后面不包含数字的所有分组 s=re.findall(r'(?P<name>\D+)(?<!\d)','java678abc891abe2345stu2454dy')#结果是:['java', 'abc', 'abe', 'stu', 'dy']12345678十、 消耗—不捕获-不参与分组的圆括号,(?:pattern)1、 实现需求参与匹配,不捕获,即不返回结果,不将匹配结果送给后面类比前置肯定匹配(?=pattern)也不捕获结果,但将匹配结果送给后面分组2、 示例如下str=''' s=http://www-1.baidu.com s=https://www-2.baidu.com s=ftp://www-3.baidu.com ''' #请注意,下面的str后面,没有re.S,否则操作有错,这里只对每一行进行正则匹配捕获 s1=re.findall(r'(?:http|https|ftp):\/\/(?P<name>.*)',str) #结果是:['www-1.baidu.com', 'www-2.baidu.com', 'www-3.baidu.com'] s1=re.findall(r'(?:http|https|ftp)(?P<name>:\/\/.*)',str) #结果是:['://www-1.baidu.com', '://www-2.baidu.com', '://www-3.baidu.com'] s1=re.findall(r'(http|https|ftp):\/\/(?P<name>.*)',str) #结果是:[('http', 'www-1.baidu.com'), ('https', 'www-2.baidu.com'), ('ftp', 'www-3.baidu.com')] s1=re.findall(r'(?:https:)(?P<name>.*)',str,re.I) #结果是:['//www-2.baidu.com']1234567891011121314151617181920十一、 前置—后置位置颠倒及对比(?:pattern)1、 实现需求r‘…(?<=pattern1)mypattern(?=pattern2) …’将后置放在前面,将前置放在后面,结果是(?<=pattern1)后置参与匹配、不捕获、消耗(?=pattern2)前置参与匹置、不捕获、消耗2、 语法结果理解1) 将后置放在前面时因为他只参与后置前一个正则表达式的匹配、捕获、消耗,所以不参与2) 将前置放在后面时因为前置只参与他后面的一个前置,对后面的内容捕获,所以本段内容匹配、消耗、不捕获3) mypattern有无分组,即圆括号,结果是一样的4) 实际测试时,如果mypattern有圆括号,则此时的前置颠到效果与加入(?:pattern)一样3、 示例如下#前置肯定与后置肯定颠倒颠颠位置后,则匹配、不捕获、消耗import restr = r'<div class="test1"><h1><span>学习大数据bigData</span></h1></div>'s1 = re.findall(r"(?<=<h1>).+?(?=</h1>)",str)#前置与后置颠倒时,则只匹配、不捕获,可以理解为后置己经参与前面一个正则的捕获了,而前置放在后面,则对前面来说,不捕获结果#结果是:['<span>学习大数据bigData</span>']s1 = re.findall(r"(?:<h1>).+?(?=</h1>)",str)#结果是:['<h1><span>学习大数据bigData</span>'],说明(?:pattern)不参与分组,但后面无分组时,则参与消耗s1 = re.findall(r"(?:<h1>)(?P<id123>.+?)(?=</h1>)",str)#结果是:['<span>学习大数据bigData</span>'],说明(?:pattern)不参与分组,但后面有分组时,则不参与消耗s1 = re.findall(r"(?:<h1>)(?P<id123>.+?)(?:</h1>)",str)#结果是:['<span>学习大数据bigData</span>'],说明(?:pattern)不参与分组,前后有分组时,则不参与消耗s1 = re.findall(r"(?=<h1>).+?(?=</h1>)",str)#结果是:['<h1><span>学习大数据bigData</span>'],前置发挥正常作用,前置放在后面时,匹配,不对前面消耗s1 = re.findall(r"(?:<h1>).+?(?=</h1>)",str)#结果是:['<h1><span>学习大数据bigData</span>'],说明(?:pattern)对后面无分组时,参与捕获、消耗s1 = re.findall(r"(?:<h1>)(.+?)(?=</h1>)",str)#结果是:['<span>学习大数据bigData</span>'],说明(?:pattern)对后面有分组时,消耗、但不参与捕获12345678910111213141516171819202122232425created by 刘明