编程

当前位置:时时彩平台 > 编程 > python 正则表达式学习笔记

python 正则表达式学习笔记

来源:http://www.mrmtshipyard.com 作者:时时彩平台 时间:2019-09-30 20:45

图片 1

正则表达式(regular expression)是一种用于匹配文本形式的强大逻辑表达式,在 Python 中的 re 模组提供了正则表达式的支持。正则表达式由一些普通字符和一些元字符(metacharacters)组成。普通字符包括大小写的字母和数字,而元字符则具有特殊的含义。

这是菜鸟学python的第46篇原创文章

当正则表达式为一个普通的字符串时,一个正则表达式的匹配行为就是一个普通的字符串查找过程。例如,正则表达式"testing"中没有包含任何元字符,它可以匹配"testing"和"testing123"等字符串,但因为大小写敏感,它不能匹配"Testing"。其他一些元字符则不会被作为普通字符来处理,它们包括 . ^ $ * + ? { [ ] | ( ) 。

阅读本文大概需要8分钟

. 会匹配除了换行以外的任何字符; w 等价于 [a-zA-Z0-9_] 会匹配单一字母、数字或下划线字符,而 W 则会匹配任何非字母、数字和下划线的单一字符; b 会匹配“单一字母、数字或下划线字符”和“任何非字母、数字和下划线的单一字符”之间的边界。 s 等价于 [ nrtf] ,会匹配一个空白字符(包括空格、换行、返回、制表符、表格), S 则匹配所有非空白字符; t n r 依次用于匹配制表符、换行符、返回符; d 等价于 [0-9] 用于匹配十进制表示的的数字。

前面讲了这么多正则表达式的知识,光说不练假把式,我觉得学习正则表达式比较好的方法就是思考,练习,再验证,再思考,下面我们先来一篇实战运用一下

^ 作为开始标记, $ 作为结束标记,分别用于标记一个字符串的开始和结束的位置。 用于一些字符的转义,比如 . 表示对于一个真实点字符的匹配, \ 表示对于一个真实反斜杠字符的匹配等。如果你对不是很确定一些字符是否需要进行转义才能匹配,你大可都加上斜杠,比如对于 @ 你写成 @ 是一定没有问题的。

1).首先我们想到最简单的是patt=r"10|11|12|13...59",但是这样太复杂了,能不能简单一点呢~~有办法的,我们来分解一下:

import re

首先这个数字是2位数

str = 'A cute word:cat!!'

数字的都是十几,二十几,三十几,四十几,五十几,所以第一位数在1到5之间,第二位数在0到9之间

match=re.search(r'word:www',str)

那么改成patt=r"[1-5][0-9]"

if match:

import re

print 'found',match.groups()

patt=r'[1-5][0-9]'

这里将用word:www',str这个正则对str进行进行匹配查找,正则表达式前的r标记了这个表达式不用做转义处理,也就是说n这种东西再被r标记了以后就不会当作换行处理,match变量将指向匹配查找的结果。

match=re.findall(patt,'10,20,30,40,2,3,59,60')

结果输出为 cat

if match:

import re
print re.search(r'..g','piiig').group()
print re.search(r'ddd','p123g').group()
print re.search(r'www','@@abcd!').group()

print match

输出结果为:iig   123  abc
注:'..g' 查找g前的两个字母
    'ddd' 查找字符串中的三个数字
    'www'查找字符串中的三个单词字符  (若为'wwww' 则输出abcd)
正则表达式中我们可以用+和*来实现重复多次的形式表达,*表示0或更多次的重复,+表示1或更多次的重复

>>['10', '20', '30', '40', '59']

import re
print re.search(r'pi+','piiig').group()
print re.search(r'pi*','pg').group()
输出:piii  p

也许有同学不服气,说有啥了不起的,我用推导列表也可以搞定,是的这个你可以写成如下:

 

str1='10,20,30,40,2,3,59,60'

 方括号的作用? 将一系列的正则字符以或的形式连接起来
import re
print re.search(r'[abc]+','xxxacbbcbbadddedede').group()
print re.search(r'[a-d]+','xxxacbbcbbadddedede').group()
输出为:acbbcbba  acbbcbbaddd
# 前者匹配了连续的由abc组成的字符串
# 后者匹配了从a到d的所有字母组成的俩许字符串
import re

print [x for x in str1.split

str = 'purple alice-b@jisuanke.com monkey dishwasher'

ifint>=10andint<=59]

match=re.search('([w.-]+)@([w.-]+)',str)

>>['10', '20', '30', '40', '59']

if match:

2).好,我们来改动一下,若把字符串改成下面这样:

print match.group()

str1='xy,10,20,30,40,62,3,59,1w'

print match.group(1)

你这个时候再用列表推导就很难处理了,又有字符,又有数字,又有字符混合数字,怎么办

print match.group(2)

写代码要好多if/else,这是时候该正则表达式威猛帅哥出场啦,为啥题目说1个小时的事3分钟搞定有道理的,接着看

输出:alice-b@jisuanke.com

import re

alice-b

str1='xy,10,20,30,40,62,3,59,1w'

jisuanke.com

patt=r'[1-5][0-9]'

注:在group()函数中加参数与不加参数的区别

match=re.findall(patt,'str1')

正则表达式用简单的一些字符的组合包含了太丰富的语义,但是它们实在太过密集了,为了把你的正则表达式写对,你可能要花上太多太多的时间。在这里,我们提供一些简单的建议帮助你更高效的对正则表达式进行调试。

if match:

你可以设计一系列放在列表里的字符串用于调试,其中一部分是可以产生符合正则表达式的结果的,另一部分是产生不符合正则表达式的结果的。请注意,在设计这些字符串时,尽可能让他们的特征表现的更为不同一些,便于覆盖到我们可能出现的各种正则表达式没有写对的错误。例如,对于一个存在

print match

  • 的正则表达式,我们可以考虑选用一个符合 * 但是不符合 + 的字符串

>>['10', '20', '30', '40', '59']

然后你可以写一个循环,依次验证每个列表内的字符串是否符合指定的某个正则表达式并且和你设定的存在另一个列表内的预期结果进行比对,如果出现了不一致的情况,则你应该考虑看看你的正则表达式是不是还需要修改,如果结果基本一致,那么我们可以考虑进一步修改我们用于调试的字符串或添加新的字符串。

看是不是很简便

除了之前用到的search方法,在结合圆括号后,我们还可以使用另一个名 为findall的方法 来匹配查找出所有的被查找字符串符合正则的结果,并得到一个结果元组为元素的列表

有了上面的思路,可以顺藤摸瓜,好我们来分析一下

import re
str = 'purple alice@jisuanke.com, blah monkey bob@abc.com blah dishwasher'
tuples=re.findall(r'([w.-]+)@([w.-]+)',str)
print tuples

1).字母我们用[a-zA-Z]来表示,只含2个字母,那就[a-zA-Z][a-zA-Z]

输出:[('alice', 'jisuanke.com'), ('bob', 'abc.com')]

2).第一个字母必须是大写的A或B或C,那就[ABC][a-zA-Z]

结合文件操作和 findall 的使用选出下面这段代码正确的输出结果

import re

test.txt 的文本内容如下

patt=r'[A-C][a-zA-Z]'

图片 2

match=re.findall(patt,'xy,1,2,3,4,Ab,w1,Cz')

 

if match:

 

print match

在用于正则表达式的 re 模组中的函数有一些可选参数,我们可以对 search() 函数或者 findall() 函数传入额外的参数来进行使用,如  re.search(pat, str, re.IGNORECASE) 中的  re.IGNORECASE 就是使用了 re 中的一个标记作为额外的参数。

>>['Ab', 'Cz']

在 re 模组中,提供了很多不同的可选参数,其中上面提到的 IGNORECASE 表示了让匹配时忽略大小写的区别;而另外一个可选参数 DOTALL 如果被添加,则会允许正则中的 . 去跨行匹配,加了这个参数以后 .* 这样的匹配方式,将可以跨行进行匹配,而不只是在行内进行。另外,还有一个可选参数是 MULTILINE ,使用它以后,对于一个多行文本组成的字符串, ^ 和 $ 将可以用于匹配每一行的开始和结束,而如果没有用它时 ^ 和 $ 只会匹配整个字符串的开始和结束。

这招在过滤邮件里面经常用到,若不用正则表达式,启用其他的方法,则很麻烦,虽然也能解决,但是不方便

除了可选参数之外,我们还需要理解一下正则匹配的“贪心情况”。假设我们有一段文字 <b>foo</b> and <i>so on</i> 而你希望匹配 (<.*>) 提取的所有 HTML 标签,你觉得结果会是怎么样呢?我们可以得到期望的 <b> ,  </b> ,  <i> ,  </i> 这样的结果吗?

比如这样的一个字符串'xy,1,2,?,123@sohu,Ab,w1,Cz,xyh,abc',我们怎么办,分析一下吧:

事实上的结果可能会有点出乎你的意料,因为  .* 这样的匹配是“贪心”的,它会尽可能去得到较长的匹配结果,因此我们会得到的是一整个 <b>foo</b> and <i>so on</i> 作为匹配出的结果。如果我们希望获得期望中的结果,我们就需要这个匹配是非贪心的,在正则表达式中,我们对于 * 和 + 这种默认贪心的匹配可以加上 ? 使之变为不贪心的。

1).首先要设计出匹配字母并且是3个字母,我们很容易想到patt=r'[a-zA-Z][a-zA-Z][a-zA-Z]'或者patt=r'[a-zA-Z]{3}'

也就是说,如果我们将 (<.*>) 改成 (<.*?>) ,正则表达式会先匹配 <b> ,然后匹配 </b> ,接下来则分别是 <i> 和 </i> 。这样的匹配结果与我们的预期完全一致。相应的,对于一些用到了 + 的情况,我们可以将 + 变为 +? 来进行非贪心的匹配。

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']

跟上面类似,大家思考一下应该很快有答案,有同学说是不是这样就可以了

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小时的时间比如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 [''.joinfor 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 [''.joinfor 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*'**

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

本文由时时彩平台发布于编程,转载请注明出处:python 正则表达式学习笔记

关键词:

上一篇:没有了

下一篇:没有了