简书收藏--Python正则表达式Python程序员联盟

正则实战秘籍分享-学会了能让1小时的工作变成3分钟

2017-01-12  本文已影响382人  菜鸟学python

这是菜鸟学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'

如何用正则去匹配 ,欢迎留言提出你的解法

上一篇下一篇

猜你喜欢

热点阅读