Python-正则表达式

1.为什么要用正则表达式

“知道[正则表达式]可能意味着用 3 步解决一个问题,而不是用 3000 步。如果
你是一个技术怪侠,别忘了你用几次击键就能解决的问题,其他人需要数天的烦琐
工作才能解决,而且他们容易犯错。”

2.使用方法

简单举例:

phoneNumRegex = re.compile(r'\d{3}-\d{3}-\d{4}')  # 创建Regex对象
mo = phoneNumRegex.search("my number is 415-555-4242") #
print('phone number found:' + mo.group())

变量名 mo 是一个通用的名称,用于 Match 对象。

这里,我们将期待的模式传递给 re.compile(),并将得到的 Regex 对象保存phoneNumRegex 中。然后我们在 phoneNumRegex 上调用 search(),向它传入想查找的字符串。查找的结果保存在变量 mo 中。在这个例子里,我们知道模式会在这个符串中找到,所以我们知道会返回一个 Match 对象。知道 mo 包含一个 Match 对象,而不是空值 None,我们就可以在 mo 变量上调用 group(),返回匹配的结果。将 mo.group()写在打印语句中,显示出完整的匹配,即 415-555-4242。

3. 正则表达式匹配更多模式

3.1 利用括号分组

phone = re.compile(r'(\d\d\d)-(\d\d\d-\d\d\d\d)')
mo = phone.search('My number is 422-333-3333')
print(mo.group(0))
print(mo.group(1))
print(mo.group(2))

假定想要将区号从电话号码中分离。添加括号将在正则表达式中创建“分组”:
(\d\d\d)-(\d\d\d-\d\d\d\d)。然后可以使用 group()匹配对象方法,从一个分组中获取匹
配的文本。
正则表达式字符串中的第一对括号是第 1 组。第二对括号是第 2 组。向 group()
匹配对象方法传入整数 1 或 2,就可以取得匹配文本的不同部分。向 group()方法传
入 0 或不传入参数,将返回整个匹配的文本。

如果想要一次就获取所有的分组,请使用 groups()方法,注意函数名的复数形式。

 mo.groups()
('415', '555-4242')
>>> areaCode, mainNumber = mo.groups()
>>> print(areaCode)
415
>>> print(mainNumber)
555-4242

如果匹配的文本中特殊字符,例如括号,就需要使用转义符(\)来将特殊符号进行转义来匹配文本。

phone1 = re.compile(r'(\(\d\d\d\)) (\d\d\d-\d\d\d\d)')
mo = phone1.search('my phone number is (415) 555-3333')
print(mo.group())

3.2 用管道匹配多个分组

字符 “|” 称为“管道”。希望匹配许多表达式中的一个时,就可以使用它。

name = re.compile(r'haha|xixi')
mo = name.search("I have a xixi and a haha")
print(mo.group())

如果haha 和 xixi 都出现在被查找的字符串中,第一次出现的匹配文本,将作为Match对象返回。

假设你希望匹配‘xiaogang’,'xiaofang','xiaoming'中的一个。因为所有这些都是以xiao开头,所以如果能够只指定一次前缀,就很方便。这可以通过括号实现。

name = re.compile(r"xiao(gang|ming|fang)")
mo = name.search("xiaogang,xiaofang,xixi,momo")
print(mo.group())

方法调用 mo.group()返回了完全匹配的文本'Batmobile',而 mo.group(1)只是返
回第一个括号分组内匹配的文本'mobile'。通过使用管道字符和分组括号,可以指定
几种可选的模式,让正则表达式去匹配。
如果需要匹配真正的管道字符,就用倒斜杠转义,即\|

3.3 用问号实现可选匹配

有时候,想匹配的模式是可选的。就是说,无论这段文本在不在,正则表达式都会认为匹配。字符?表名它1前面的分组在这个模式中是可选的。

格式: (ha)?
name = re.compile(r"ka(la)?ka") mo = name.search('kaka,kalaka') print(mo.group())

3.4 用星号匹配零次或多次

*(称为星号)意味着“匹配零次或多次”,即星号之前的分组,可以在文本中出现任意次。它可以完全不存在,或一次又一次地重复

name = re.compile(r"(ha)*xiaojiao")
mo = name.search("I have a hahahahahaxiaojiao")
print(mo.group())

3.5 用加号匹配一次或多次

*意味着“匹配零次或多次”,+(加号)则意味着“匹配一次或多次”。星号不要求
分组出现在匹配的字符串中,但加号不同,加号前面的分组必须“至少出现一次”。这不
是可选的。

name = re.compile(r"(ao)+jiao")
mo = name.search("I have a aojiao") # 一条
mo = name.search("I have a aoaojiao") #多条
print(mo.group())

如果需要匹配真正的加号字符,在加号前面加上倒斜杠实现转义:\+。

3.6 用花括号匹配特定次数

如果想要一个分组重复特定次数,就在正则表达式中该分组的后面,跟上花括
号包围的数字。例如,正则表达式(Ha){3}将匹配字符串'HaHaHa',但不会匹配'HaHa',因为后者只重复了(Ha)分组两次。

除了一个数字,还可以指定一个范围,即在花括号中写下一个最小值、一个逗号和
一个最大值。例如,正则表达式(Ha){3,5}将配'HaHaHa'、'HaHaHaHa'和'HaHaHaHaHa'。
也可以不写花括号中的第一个或第二个数字,不限定最小值或最大值。Ha){3,}将匹配 3 次或更多次实例,(Ha){,5}将匹配 0 到 5 次实例。如果有五个ha则返回五个而不是三个

name = re.compile(r"(ha){3}")
mo = name.search("hahaha, I win")
print(mo.group())

3.7 贪心和非贪心匹配

Python 的正则表达式默认是“贪心”的,这表示在有二义的情况下,它们会尽
可能匹配最长的字符串。花括号的“非贪心”版本匹配尽可能最短的字符串,即在
结束的花括号后跟着一个问号。

name = re.compile(r"(ha){3,5}")
mo = name.search("hahahahahaha, I win")
print(mo.group())

name = re.compile(r"(ha){3,5}?")
mo = name.search("hahahahahaha, I win")
print(mo.group())

3.8 findall()方法

除了search方法外,Regex对象也有一个findall()方法。search()将返回一个Match
对象,包含被查找字符串中的“第一次”匹配的文本,而 findall()方法将返回一组
字符串,包含被查找字符串中的所有匹配。

num = re.compile(r"\d\d\d")
mo = num.findall("433,324,This is a box")
print(mo)

另一方面,findall()不是返回一个 Match 对象,而是返回一个字符串列表,只要
在正则表达式中没有分组。列表中的每个字符串都是一段被查找的文本,它匹配该
正则表达式。

如果在正则表达式中有分组,那么 findall 将返回元组的列表。每个元组表示一个找
到的匹配,其中的项就是正则表达式中每个分组的匹配字符串。

name = re.compile('(\d\d) (\d\d)')
mo = name.findall("42 33 34 44, xixixi")
print(mo)

[('42', '33'), ('34', '44')]

作为 findall()方法的返回结果的总结,请记住下面两点:
1.如果调用在一个没有分组的正则表达式上,例如\d\d\d-\d\d\d-\d\d\d\d,方法
findall()将返回一个匹配字符串的列表,例如['415-555-9999', '212-555-0000']。
2.如果调用在一个有分组的正则表达式上,例如(\d\d\d)-(\d\d\d)-(\d\d\d\d),方
法 findall()将返回一个字符串的元组的列表(每个分组对应一个字符串),例如[('415',
'555', '1122'), ('212', '555', '0000')]

3.9 字符分类

缩写字符分类 表示
\d 0到9的任何数字
\D 除0到9的数字以外的任何字符
\w 任何字母、数字或下划线字符(可以认为是匹配“单词”字符)
\W 除字母、数字和下划线以外的任何字符
\s 空格、制表符或换行符(可以认为是匹配“空白”字符)
\S 除空格、制表符和换行符以外的任何字符

 

name = re.compile(r'\d+\s\w')
mo = name.search("a,2 b")
print(mo.group())

2 b

正则表达式\d+\s\w+匹配的文本有一个或多个数字(\d+),接下来是一个空白字
符(\s),接下来是一个或多个字母/数字/下划线字符(\w+)。findall()方法将返回所有匹
配该正则表达式的字符串,放在一个列表中

3.10 建立自己的字符分类

匹配 含义
[aeiouAEIOU] 匹配所有元音字符,无论大小写
[a-zA-Z0-9] 匹配所有小写字母、大写字母和数字
[^aeiouAEIOU] 非字符类。非字符类将匹配不在这个字符类中的所有字符

请注意,在方括号内,普通的正则表达式符号不会被解释。这意味着,你不需
要前面加上倒斜杠转义.、*、?或()字符。

name = re.compile(r'[a-zA-Z0-9]')
mo = name.findall("I have a dream")
print(mo)

['I', 'h', 'a', 'v', 'e', 'a', 'd', 'r', 'e', 'a', 'm']

 

3.11 插入字符和美元字符

可以在正则表达式的开始处使用插入符号(^),表明匹配必须发生在被查找文
本开始处。类似地,可以再正则表达式的末尾加上美元符号($),表示该字符串必
须以这个正则表达式的模式结束。可以同时使用^和$,表明整个字符串必须匹配该
模式,也就是说,只匹配该字符串的某个子集是不够的。

 re.compile(r'^\d+$')

3.12 通配字符

在正则表达式中,.(句点)字符称为“通配符”。它匹配除了换行之外的所有
字符。

name = re.compile(r'.cat')
mo = name.findall('xcat,ycat,jcat')
print(mo)

['xcat', 'ycat', 'jcat']

有时候想要匹配所有字符串。例如,假定想要匹配字符串'First Name:',接下来
是任意文本,接下来是'Last Name:',然后又是任意文本。可以用点-星(.*)表示“任
意文本”。回忆一下,句点字符表示“除换行外所有单个字符”,星号字符表示“前
面字符出现零次或多次”。

name = re.compile(r'First Name:(.*) Last Name:(.*)')
mo = name.search('First Name: AI Last Name:Sweigart')
print(mo.group())

First Name: AI Last Name:Sweigart

 

posted @ 2019-07-09 16:19  山重水复疑无路  阅读(277)  评论(0编辑  收藏  举报