这是菜鸟学python的第46篇原创文章
阅读本文大概需要8分钟
前面讲了这么多正则表达式的知识,光说不练假把式,我觉得学习正则表达式比较好的方法就是思考,练习,再验证,再思考,下面我们先来一篇实战运用一下
一. 关于简单的字符串的例子
1.设计一个正则来过滤一个字符串序列中的10到59
1).首先我们想到最简单的是patt=r"10|11|12|13...59",但是这样太复杂了,能不能简单一点呢~~有办法的,我们来分解一下:
首先这个数字是2位数
数字的都是十几,二十几,三十几,四十几,五十几,所以第一位数在1到5之间,第二位数在0到9之间
那么改成patt=r"[1-5][0-9]"
import re
patt=r'[1-5][0-9]'
match=re.findall(patt,'10,20,30,40,2,3,59,60')
if match:
print match
>>['10', '20', '30', '40', '59']
也许有同学不服气,说有啥了不起的,我用推导列表也可以搞定,是的这个你可以写成如下:
str1='10,20,30,40,2,3,59,60'
print [x for x in str1.split(',')\
ifint(x)>=10andint(x)<=59]
>>['10', '20', '30', '40', '59']
2).好,我们来改动一下,若把字符串改成下面这样:
str1='xy,10,20,30,40,62,3,59,1w'
你这个时候再用列表推导就很难处理了,又有字符,又有数字,又有字符混合数字,怎么办
写代码要好多if/else,这是时候该正则表达式威猛帅哥出场啦,为啥题目说1个小时的事3分钟搞定有道理的,接着看
import re
str1='xy,10,20,30,40,62,3,59,1w'
patt=r'[1-5][0-9]'
match=re.findall(patt,'str1')
if match:
print match
>>['10', '20', '30', '40', '59']
看是不是很简便
2.过滤字符串中的只含2个字符的字母,并且第一个字母是大写A或B或C
有了上面的思路,可以顺藤摸瓜,好我们来分析一下
1).字母我们用[a-zA-Z]来表示,只含2个字母,那就[a-zA-Z][a-zA-Z]
2).第一个字母必须是大写的A或B或C,那就[ABC][a-zA-Z]
import re
patt=r'[A-C][a-zA-Z]'
match=re.findall(patt,'xy,1,2,3,4,Ab,w1,Cz')
if match:
print match
>>['Ab', 'Cz']
这招在过滤邮件里面经常用到,若不用正则表达式,启用其他的方法,则很麻烦,虽然也能解决,但是不方便
3.过滤一个字符串中的含3个字母的独立字符
比如这样的一个字符串'xy,1,2,?,123@sohu,Ab,w1,Cz,xyh,abc',我们怎么办,分析一下吧:
1).首先要设计出匹配字母并且是3个字母,我们很容易想到patt=r'[a-zA-Z][a-zA-Z][a-zA-Z]'或者patt=r'[a-zA-Z]{3}'
import re
patt=r'[a-zA-Z]{3}'
match=re.findall(patt,'xyhh,a,1,2,?,123@sohu,Ab,w1,Cz,xyh,abc')
if match:
print match
>>['xyh', 'soh', 'xyh', 'abc']
2).继续分析
上面的解决方案虽然解决了一部分的问题,但是很明显结果不完全正确,因为"xyhh","123@sohu"这样的字符组是我们不想要的
我们真正想要的是'xyh'和'abc',怎么办呢...我们可以这样改:patt=r'\b[a-zA-Z]{3}\b'
我们加上了"\b"表示匹配单词的边界,这样3个字母就是独立的字符组
import re
patt=r'\b[a-zA-Z]{3}\b'
match=re.findall(patt,'xyhh,a,1,2,?,123@sohu,Ab,w1,Cz,xyh,abc')
if match:
print match
>>
['xyh', 'abc']
4.过滤一个字符串中的含3个字母的字符,并且最后一个字母是z
跟上面类似,大家思考一下应该很快有答案,有同学说是不是这样就可以了
import re
patt=r'[a-zA-Z][a-zA-Z][z]+'
match=re.findall(patt,'xy,1,2,3,4,Ab,w1,Cz,xyh,xyz,xyzz')
if match:
print match
>>['xyz', 'xyzz']
不对啊,怎么把'xyzz'弄进来来,大家思考一下为啥'+'不行,或者换成'*'行不行,欢迎留言讨论
正确的应该加'\b'来框定单词边界
import re
patt=r'\b[a-zA-Z][a-zA-Z][z]\b'
match=re.findall(patt,'xy,1,2,3,4,Ab,w1,Cz,xyh,xyz,xyzz')
if match:
print match
>>['xyz']
二. 匹配12小时制时间
一般的12小时的时间比如8:30am或者12:15pm,这样的时间,我们应该如何用正则来匹配过滤呢,大家有没有思路,先思考2分钟,然后再往下看:
第一步:问题分解,时刻肯定是数字,所以应该是如下的格式
import re
patt=r'[0-9][0-9]:[0-9][0-9]am|[0-9][0-9]:[0-9][0-9]pm'
match=re.findall(patt,'10:00am,99:90am,8:00am,12:49pm,3:51pm,15:00pm')
ifmatch:
printmatch
>>['10:00am', '99:90am', '12:49pm','15:00pm']
第二步:上面第一步虽然解析出了'10:00am', '12:49pm',but没有过滤掉错误的时间日期'99:90am','15:00pm',更重要的是没有解析出8:00am,3:51pm,因为小时数可以是一位,不一定要两位,而且分钟只能是0-5,怎么破,我们来改动一下吧:
patt=r'[0-9][0-9]:[0-5][0-9]am|[0-9][0-9]:[0-5][0-9]pm'
改成patt=r'[0-9][0-9]:[0-5][0-9][ap]m'
再来仔细看小时数,如果小时数是一个两位数
1),第一位只能是1,用[1-9]匹配一位数
2),如果是两位数,那么1[012]匹配两位数
然后再改成patt=r'1[0-2]|[1-9]:[0-5][0-9][ap]m'#注意看加了一个或'|'
import re
patt=r'(1[0-2]|[1-9])(:)([0-5][0-9][ap]m)'
match=re.findall(patt,'10:00am,99:90am,8:00am,12:49pm,3:51pm,15:00pm')
if match:
print [''.join(x)for x in match]
>>['10:00am', '8:00am', '12:49pm', '3:51pm','5:00pm']
第三步:经过上面2步已经大功告成了,但是15:00pm被匹配成5:00pm,怎么破,加个单词边界就可以搞定:
import re
patt=r'\b(1[0-2]|[1-9])(:)([0-5][0-9][ap]m)'
match=re.findall(patt,'10:00am,99:90am,8:00am,12:49pm,3:51pm,15:00pm')
if match:
print [''.join(x)for x in match]
>>['10:00am', '8:00am', '12:49pm', '3:51pm']
结束之前:留一道思考题
如果24小时制时间比如23:23pm,或者29:19pm(不正确的格式)
'10:00am,99:90am,8:00am,19:19pm:14:00pm,5:xm,23:23pm,29:19pm'
如何用正则去匹配 ,欢迎留言提出你的解法
网友评论