Python--模块之re

re模块

就其本质而言,正则表达式(或 RE)是一种小型的、高度专业化的编程语言,(在Python中)它内嵌在Python中,并通过 re 模块实现。正则表达式模式被编译成一系列的字节码,然后由用 C 编写的匹配引擎执行。

 

字符串是编程时涉及到的最多的一种数据结构,对字符串进行操作的需求几乎无处不在。比如判断一个字符串是否是合法的Email地址,虽然可以编程提取@前后的子串,再分别判断是否是单词和域名,但这样做不但麻烦,而且代码难以复用。

正则表达式是一种用来匹配字符串的强有力的武器。它的设计思想是用一种描述性的语言来给字符串定义一个规则,凡是符合规则的字符串,我们就认为它“匹配”了,否则,该字符串就是不合法的。

因为正则表达式也是用字符串表示的,所以,我们要首先了解如何用字符来描述字符。

字符匹配(普通字符,元字符):

1 普通字符:大多数字符和字母都会和自身匹配
              >>> re.findall('alvin','yuanaleSxalexwupeiqi')
                      ['alvin'] 

2 元字符:. ^ $ * + ? { } [ ] | ( ) \

 

元字符之. ^ $

元字符之* + ? { }

要匹配变长的字符,在正则表达式中,用*表示任意个字符(包括0个),用+表示至少一个字符,用?表示0个或1个字符,用{n}表示n个字符,用{n,m}表示n-m个字符:

# 匹配一个数字包括整型和浮点型
ret=re.findall('\d+\.?\d*','12.45,34,0.05,109')

print(ret)
运行结果:
['12.45', '34', '0.05', '109']

贪婪匹配

正则匹配默认是贪婪匹配,也就是匹配尽可能多的字符。

非贪婪匹配

在满足匹配时,匹配尽可能短的字符串,使用?来表示非贪婪匹配

ret1=re.findall('131\d+','1312312312') #-------------------------------------------------贪婪匹配
print(ret1)  

ret=re.findall('131\d+?','1312312312') #-------------------------------------------------非贪婪匹配/惰性匹配
print(ret)
运行结果:
['1312312312']
['1312']

注意:前面的*,+,?等都是贪婪匹配,也就是尽可能匹配,后面加?号使其变成惰性匹配

几个常用的非贪婪匹配Pattern

 

*? 重复任意次,但尽可能少重复
+? 重复1次或更多次,但尽可能少重复
?? 重复0次或1次,但尽可能少重复
{n,m}? 重复n到m次,但尽可能少重复
{n,}? 重复n次以上,但尽可能少重复

.*?的用法:

 

. 是任意字符
* 是取 0 至 无限长度
? 是非贪婪模式。
何在一起就是 取尽量少的任意字符,一般不会这么单独写,他大多用在:
.*?x

就是取前面任意长度的字符,直到一个x出现

 

元字符之转义符 \

1、反斜杠后边跟元字符去除特殊功能,比如\.

2、反斜杠后边跟普通字符实现特殊功能,比如\d

\d  匹配任何十进制数;      它相当于类 [0-9]。
\D  匹配任何非数字字符;    它相当于类 [^0-9]。
\s  匹配任何空白字符;      它相当于类 [ \t\n\r\f\v]。
\S  匹配任何非空白字符;    它相当于类 [^ \t\n\r\f\v]。
\w  匹配任何字母数字字符;   它相当于类 [a-zA-Z0-9]。
\W  匹配任何非字母数字字符; 它相当于类 [^a-zA-Z0-9]
\b  匹配一个特殊字符边界,比如空格 ,&,#等

让我们看一下\b的应用:

ret=re.findall(r'I\b','I am LIST')
print(ret)
运行结果:
['I']
ret=re.findall(r'c\\b',r'abc\be')
print(ret)
运行结果:
['c\\b']

# \b是特殊符号所以,'abc\be'前面需要加r

接下来我们试着匹配下“abc\le”中的‘c\l’:

import re

# ret=re.findall('c\l','abc\le')  #---------------------不正确
# print(ret)

# ret=re.findall('c\\l','abc\le')  #---------------------不正确
# print(ret)
#
# ret=re.findall('c\\\\l','abc\le')  #---------------------正确
# print(ret)
# #
# ret=re.findall(r'c\\l','abc\le')  #---------------------正确
# print(ret)
运行结果:
报错
报错
['c\\l']
['c\\l']

元字符之分组 ()

除了简单地判断是否匹配之外,正则表达式还有提取子串的强大功能。()表示的就是要提取的分组(Group)。

m = re.findall(r'(ad)+', 'add')
print(m)

ret = re.search('(?P<id>\d{2})/(?P<name>\w{3})', '23/com')
print(ret.group())
print(ret.group('id')) 
运行结果:
['ad']
23/com
23

如果正则表达式中定义了组,就可以在Match对象上用group()方法提取出子串来。

注意到group(0)永远是原始字符串,group(1)group(2)……表示第1、2、……个子串。

元字符之|

ret=re.search('(ab)|\d','rabhdg8sd')
print(ret)
print(ret.group())
运行结果:
<_sre.SRE_Match object; span=(1, 3), match='ab'>
ab

元字符之字符集[]

 

# --------------------------------------------字符集[]
ret = re.findall('a[bc]d', 'acd')
print(ret)  # ['acd']

ret = re.findall('[a-z]', 'acd')
print(ret)  # ['a', 'c', 'd']

ret = re.findall('[.*+]', 'a.cd+')
print(ret)  # ['.', '+']

# 在字符集里有功能的符号: - ^ \

ret = re.findall('[1-9]', '45dha3')
print(ret)  # ['4', '5', '3']

ret = re.findall('[^ab]', '45bdha3')
print(ret)  # ['4', '5', 'd', 'h', '3']

ret = re.findall('[\d]', '45bdha3')
print(ret)  # ['4', '5', '3']

注意以上一点。

re模块下的常用方法

import re

ret=re.findall('a', 'alvin yuan')  # 返回所有满足匹配条件的结果,放在列表里
print(ret)  #['a', 'a']

ret=re.search('a', 'alvin yuan').group()
print(ret)  #a

# 函数会在字符串内查找模式匹配,只到找到第一个匹配然后返回一个包含匹配信息的对象,该对象可以
# 通过调用group()方法得到匹配的字符串,如果字符串没有匹配,则返回None。


ret=re.match('a', 'abc').group()  # 同search,不过仅在字符串开始处进行匹配
print(ret)  #a

ret = re.split('[ab]', 'abcd')  # 先按'a'分割得到''和'bcd',再对''和'bcd'分别按'b'分割
print(ret)  # ['', '', 'cd']

ret = re.sub('\d', 'abc', 'alvin5yuan6', 1)
print(ret)  #alvinabcyuan6

ret = re.subn('\d', 'abc', 'alvin5yuan6')
print(ret)  #('alvinabcyuanabc', 2)

obj = re.compile('\d{3}')   #编译 
ret = obj.search('abc123eeee') print(ret.group()) # 123

当我们在Python中使用正则表达式时,re模块内部会干两件事情

1.
编译正则表达式,如果正则表达式的字符串本身不合法,会报错;
2.用编译后的正则表达式去匹配字符串。
  如果一个正则表达式要重复使用几千次,出于效率的考虑,我们可以预编译该正则表达式,接下来重复使用时就不需要编译这个步骤了,直接匹配:



ret = re.finditer('\d', 'ds3sy4784a')
print(ret)  #<callable_iterator object at 0x0000000001DE5BE0>

print(next(ret).group())  #3
print(next(ret).group())  #4

注意:

1 findall的优先级查询:

import re

ret = re.findall('www.(baidu|oldboy).com', 'www.oldboy.com')
print(ret)  # ['oldboy']     这是因为findall会优先把匹配结果组里内容返回,如果想要匹配结果,取消权限即可

ret = re.findall('www.(?:baidu|oldboy).com', 'www.oldboy.com')
print(ret)  # ['www.oldboy.com']

2 split的优先级查询:

ret=re.split("\d+","yuan2egon56alex")
print(ret)

ret=re.split("(\d+)","yuan2egon56alex")
print(ret)
结果:
['yuan', 'egon', 'alex']
['yuan', '2', 'egon', '56', 'alex']

 作业:

1、 匹配一段文本中的每行的邮箱
import re
ret=re.findall("\w+@\w+\.(?:com|cn|cc)",s)


2、 匹配一段文本中的每行的时间字符串,比如:‘1990-07-12’;
ret=re.findall('(?:[1-2]\d{3})-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12]\d|3[0-1])',s)


3、 匹配一段文本中所有的身份证数字。
ret=re.findall('[1-9]\d{16}[\dx]',s)

4、 匹配qq号。(腾讯QQ号从10000开始)
ret=re.findall('[1-9]\d{4,}',s)

5、 匹配一个浮点数。
ret=re.findall('\d+\.?\d*',s)

6、 匹配汉字。
ret=re.findall('[\u4e00-\u9fa5]+',s)

7、 匹配出所有整数
ret=re.findall('-?\d+\.\d*|(-?\d+)',s)

 

posted @ 2017-07-03 16:41  始怡  阅读(279)  评论(0编辑  收藏  举报