Python - 正则表达式
一、使用正则和不使用正则区别
在不使用正则的情况下来匹配一个电话号码:
#在一段文本中查找电话号码 例 331-896-7854
def isPhoneNumber(number):
if len(number) != 12: #首先检查电话号码是否是12位数
return False
for i in range(0,3):
if not number[i].isdecimal(): #判断前三位是不是数字
return False
if number[3] != '-': #判断第四位是不是 -
return False
for i in range(4,7):
if not number[i].isdecimal():
return False
if number[7] != '-':
return False
for i in range(8,12):
if not number[i].isdecimal():
return False
return True
text = 'you can contact me at 331-896-7854. 400-400-8888 is my office' #待查找的文字
for i in range(len(text)):
check = text[i:i+12] #因为电话号码是12位,所以将每段12个字符传入 判断
if isPhoneNumber(check):
print('the phone number found:' + check)
print('Done')
执行后
the phone number found:331-896-7854 the phone number found:400-400-8888 Done使用正则来匹配
phoneNumRegex = re.compile(r'\d\d\d-\d\d\d-\d\d\d\d')
#re.compile 后面传入一个字符串,表示正则表达式,使用原始字符串更方便
ret = phoneNumRegex.search('My number is 415-555-4242.').group()
#使用search 的方法 根据设置的正则模式,返回一个Match对象,在Match对象中有个group的方法,返回被查找的实际的文本
print('The phone number found :' + ret)
执行后
The phone number found :415-555-4242
二、利用括号分组
phoneNumRegex = re.compile(r'(\d\d\d)-(\d\d\d-\d\d\d\d)')
#第一个括号表示第一组,第二个
ret = phoneNumRegex.search('My number is 415-555-4242.')
# 向group中传入整数1 或 2 就可以匹配不同的部分,如果传入0或者不传入,即匹配整个文本
print('The phone number found :' + ret.group(1)) >>The phone number found :415
print('The phone number found :' + ret.group(2)) >>The phone number found :555-4242
print('The phone number found :' + ret.group()) >>The phone number found :415-555-4242
如果一次想获取所有的分组,使用groups()方法
print(ret.groups()) >> ('415', '555-4242')
如果电话号码是(415)-555-4242,匹配的时候想匹配括号,那么可以使用转义字符
phoneNumRegex = re.compile(r'(\(\d\d\d\))-(\d\d\d-\d\d\d\d)')
……
print(ret.groups()) >> ('(415)', '555-4242')
三、用管道匹配多个分组
字符| 成为管道,相当于或,使用在正则表达式中,r'superman|batman' ,这个正常表达式可以匹配superman或者匹配batman
import re
heroRegex = re.compile(r'superman|batman')
ret = heroRegex.search('superman and batman') #当找到第一个符合正则表达式的模式的时候,就返回值(使用findall可以匹配所有符合规则的)
print(ret.group())
四、其他方法
? 表明他前面的分组是可选的,存在0个或者1个 \? 匹配问号 * 匹配*前面的分组0次或多次,可以在匹配的文本中出现任意次,也可以完全不存在 \* 匹配星号 + 匹配+前面的分组一次到多次, 但是至少出现一次, 如果匹配内容没有出现,那么值为None \+ 匹配加号 ^ 匹配以什么开头 $ 匹配以什么结尾 . 匹配除换行之外的所有字符,只能匹配一个字符 .* 匹配除换行以外任意文本,贪心匹配,匹配最长的部分,如果把re.DOTALL作为第二个参数传入re.compile,可以匹配所有包括换行 .*?匹配除换行以外任意文本,非贪心匹配,匹配尽可能短的
五、花括号
- 想要一个分组重复特定次数,就在正则表达式中该分组的后面,跟上花括号包围的数字。
- 花括号中还可以指定范围,比如(ha){3,5} 那么这个正则表达式可以匹配'hahaha'、'hahahaha'、'hahahahaha'
- 花括号中可以不写第一个数字或第二个数字,不限定最小值或最大值,比如(ha){3,}匹配三次或更多、(ha){,5}匹配零到五次
六、贪心和非贪心匹配
- python中默认是贪心匹配,在有选择的情况下,他们会尽可能匹配最长的字符串
- 花括号的非贪心版本,在花括号结尾加一个?,这样匹配的时候就尽可能找最短的字符串, 这里体现了?在正则表达式中的另一个作用
#贪心匹配
>>> tx = re.compile(r'(ha){3,5}')
>>> tx.search('hahahahaha').group()
'hahahahaha'
#非贪心匹配
>>> tx = re.compile(r'(ha){3,5}?')
>>> tx.search('hahahahaha').group()
'hahaha'
七、findall
- findall:
- 没有分组时,返回一个字符串列表
- 有分组时,返回元组列表,每个元组表示找到的匹配
- 匹配所有符合正则模式的文本
- search:
- 返回一个Match对象
- 匹配第一个符合正则模式的文本
#没有分组
>>> phoneNumRegex = re.compile(r'\d\d\d-\d\d\d-\d\d\d\d')
>>> phoneNumRegex.findall('cell:415-555-9999 work:212-555-1234')
['415-555-9999', '212-555-1234']
#有分组
>>> phoneNumRegex = re.compile(r'(\d\d\d)-(\d\d\d)-(\d\d\d\d)')
>>> phoneNumRegex.findall('cell:415-555-9999 work:212-555-1234')
[('415', '555', '9999'), ('212', '555', '1234')]
八、字符分类
- \d #0到9任何数字
- \D #除0到9的数字以外的任何字符
- \w #任何字母、数字或下划线字符(可以认为是匹配“单词”字符)
- \W #除字母、数字和下划线以外的任何字符
- \s #空格、制表符或换行符(可以认为是匹配“空白”字符)
- \S #除空格、制表符和换行符以外的任何字符
>>> vowe1Regex = re.compile(r'[aeiouAEIOU]')
>>> vowe1Regex.findall('RoboCop ests baby food. BABY FOOD.')
['o', 'o', 'o', 'e', 'a', 'o', 'o', 'A', 'O', 'O']
- 也可以是用- 表示字母或数字的范围,例如,[a-zA-Z0-9]匹配所有大小写字母和数字
- 在[ ]中普通的正则表达式符号不会被解释,在[ ]中若使用 [. * ?]不需要转义
- 在[ ]左括号后加上一个字符^,就可以得到“非字符类“,非字符类将匹配不再这个字符类中的所有字符。
>>> vowe1Regex = re.compile(r'[^aeiouAEIOU]')
>>> vowe1Regex.findall('RoboCop ests baby food. BABY FOOD.')
['R', 'b', 'C', 'p', ' ', 's', 't', 's', ' ', 'b', 'b', 'y', ' ', 'f', 'd', '.', ' ', 'B', 'B', 'Y', ' ', 'F', 'D', '.']
九、不区分大小写的匹配
通常正则表达式用指定的大小写匹配文本,例如下面道德正则表达式,匹配完全不同的字符串:
import re
# regex1 = re.compile('RoboCop')
# regex2 = re.compile('ROBOCOP')
# regex3 = re.compile('robOcop')
# regex4 = re.compile('RobocOp')
robocop = re.compile(r'robocop',re.I) #如果匹配的时候想不区分大小写,可以向re.compile()传入re.IGNORECASE 或者re.I 作为第二个参数
ret = re.search(robocop,'RobOCop protects the innocent').group()
print(ret) >>> 执行后,RobOCop
#传入re.VERBOSE 作为第二个参数 忽略行尾#后面的注释,可在多行正则表达式字符串中使用
re.compile(r'''(
(\d{3}|\(\d{3}\))? #area code
(\s|-|\.)? #separator
\d{3} #first 3 digit
(\s)|-|\. #seeparator
\d{4} #last 4 digits
(\s*(ext|x|ext.)\s*\d{2,5})? #extension
)''',re.VERBOSE)
十、sub()方法替换字符串
正则表达式不仅可以找到文本,还可以用新的文本替换这些模式。 Regex对象的sub()方法需要传入两个参数,第一个参数是一个字符串,用于取代发现的匹配。第二个参数是一个字符串,即被匹配的字符串
import re
#例1
s = 'my name is alex durand'
nameRegex = re.compile(r'alex \w+')
new_s = nameRegex.sub('kevin',s)
print(new_s) #>>: my name is kevin
#例2
s = 'alex durand told alex kevin that alex jin knew alex liang was a double agent'
nameRegex = re.compile(r'alex (\w\w)\w*')
new_s = nameRegex.sub(r'\1*****',s) #1 代表第一个分组(\w\w)中的内容, 后面\w*匹配的内容都用*代替
print(new_s) #>>: du***** told ke***** that ji***** knew li***** was a double agent
十一、match方法及分组
import re
# re.match() #从头匹配,
origin = 'hello alex bcd alex 1ge alex acd 19'
r = re.match("h\w+",origin)
print(r.group()) #>> hello # #获取匹配到的所有的结果,对于mathch,不管是分组还是不分组,group匹配到的都是对照匹配规则
#分组 获取符合规则的字符,然后再获取前面得到的字符串中分组里的内容
r = re.match("h(\w+)",origin)
print(r.groups()) #>>('ello',) #获取模型中匹配到的分组结果
r = re.match("h(?P尖括号key尖括号\w+)",origin) #在括号内加入 ?P尖括号key尖括号 设置key的值, P要大写
print(r.groupdict()) #>> {'key': 'ello'} #获取模型中匹配到的分组中所执行的key的组
十二、search方法
# re.search() #浏览全部字符串,匹配第一个符合规则的字符串
origin = 'hello alex bcd alex 1ge alex acd 19'
r = re.search("a(\w+)",origin) #根据规则在字符串中查找,直到找到想对应的规则
print(r.group()) #>> alex
r = re.search("a(\w+).*(?P\d)$",origin)
print(r.groups()) #>> ('lex', '9')
print(r.groupdict()) #>> {'name': '9'}
评论
发表评论