python(01) 正则表达式
Cory Doctorow声称 应该在教授编程之前,先教授正则表达式:
知道[正则表达式]可能意味着用3步解决一个问题,而不是用3000步。如果你是一个技术怪侠,别忘了用几次击健就能解决的问题,其他人需要数天的繁琐工作才能解决,而且他们容易犯错。
练习:在字符串中查找电话号码,已知:3个数字,一个短横线,3个数字,一个短横线,再是4个数字,如:415-555-4242。
- 不用正则表达式
def isPhoneNumber(text):
if len(text) != 12:
return False
for i in range(0,3):
if not text[i].isalnum():
return False
if text[3] != '-':
return False
for i in range(4,7):
if not text[i].isalnum():
return False
if text[7] != '-':
return False
for i in range(8,12):
if not text[i].isalnum():
return False
return True
单个调用
print('415-555-4242 is a phone number:')
print(isPhoneNumber('415-555-4242'))
print('Moshi moshi is a phone number:')
print(isPhoneNumber('Moshi moshi'))
循环调用
message = 'Call me at 415-555-1011 tomorrow. 415-555-9999 is my office.'
for i in range(len(message)):
chunk = message[i:i+12]
if isPhoneNumber(chunk):
print('Phone number found:' + chunk)
print('Done')
执行结果
415-555-4242 is a phone number:
True
Moshi moshi is a phone number:
False
Phone number found:415-555-1011
Phone number found:415-555-9999
Done
Process finished with exit code 0
- 改成正则表达式
import re
phoneNumberRegex = re.compile(r'\\\\d{3}-\\\\d{3}-\\\\d{4}')
mo = phoneNumberRegex.search('My number is 415-555-4242')
print('Phone number found: ' + mo.group())
执行结果
Phone number found: 415-555-4242
总结使用正则表达式四步
- 用import re 导入正则表达式模块。
- 用re.compile()函数创建一个Regex对象(使用原始字符串)
- 向Regex对象的search()方法传入想查找的字符串。它返回一个Match对象。
- 调用Match对象的group()方法,返回实际匹配文本的字符串。
推荐学习:http://regexpal.com/
- 更强大的功能
-
利用括号分组
分组:(\\d\\d\\d)-(\\d\\d\\d-\\d\\d\\d\\d)
group()=group(0)匹配所有
group(1) 匹配(\\d\\d\\d)
group(2) 匹配(\\d\\d\\d-\\d\\d\\d\\d)
groups()多个值的元组--使用的多重复制的技巧
\\(和\\)转义字符匹配实际的括号 -
用管道匹配多个分组
r'Batman|Tina Fey'
\\|匹配真正的管道字符
3)用问号实现可选匹配
r'Bat(wo)?man'
匹配0次或一次
\\?匹配真正的问号字符
4)用星号匹配零次或多次
r'Bat(wo)man'
\\匹配真正的星号字符
5)用加号匹配一次或多次
r'Bat(wo)+man'
\\+匹配真正的加号字符
6)用花括号匹配特定次数
r'(Ha){3}' --重复3次
r'(Ha){3,5}' --重复3到5次 ----贪心匹配,如有可能重复5次
r'(Ha){,5}'--重复0到5次
r'(Ha){3,}'--重复3次或更多次
r'(Ha){3,5}?' -----非贪心匹配 ,重复3次就可以啦
-
search()和findall()区别
search--返回第一次匹配的文字
findall()--返回所有匹配的组 -
字符分类
\\d ----------0到9的任何数字
\\D----------除0-9的数字以外的任何字符
\\w---------任何字母、数字或下划线字符
\\W---------除字母、数字和下划线以外的任何字符
\\s----------空格、制表符或换行符--空白
\\S---------除空格、制表符和换行符以外的任何字符
成对出现,只记三个即可(d w s),其他三个反推。 -
使用[]建立自己的字符分类
[] 中0-5表示从0到5
插入字符--表示除了这个字符以外的任意字符
10)插入字符和美元字符
插入字符-----表示以这个为开始
美元字符-----表示以这个为结束
- 通配字符
句点字符. 匹配一个字符(除换行之外的)
点星.* 匹配所有字符 ---贪心模式
.? 非贪心模式
re.compile('.',re.DOTALL) 匹配所有包括换行
书籍看到这里,看到作者总结,真的特别简洁,差距就是连整理都不到更好
- 更复杂更强大的功能
- 用sub()方法替换字符串
>>> namesRegex = re.compile(r'Amy \\\\w+')
>>> namesRegex.sub('QingQian',' Amy like apple')
' QingQian apple'
>>> namesRegex = re.compile(r'Amy')
>>> namesRegex.sub('QingQian',' Amy like apple')
' QingQian like apple'
>>>
2)管理复杂正则表达式
phoneRegex = re.compile(r'''(
(\\\\d{3}|\\\\(\\\\d{3}\\\\))? # area code
(\\\\s|-|\\\\.)? # separator
\\\\d{3} # first 3 digits
(\\\\s|-|\\\\.) # separator
\\\\d{4} # last 4 digits
(\\\\s*(ext|x|ext.)\\\\s*\\\\d{2,5})? # extension
)''',re.VERBOSE)
代码应该就有代码的优雅
- 传递多个参数
someRegexValue = re.compile('foo' , re.IGNORECASE | re.DOTALL | re.VERBOSE)
compile()默认只接受一个值作为第二参数,通过管道| 对变量做组合进行传递。
- 实践:电话号码和E-mail地址提取程序
在网页/文章中找出所有电话号码和E-mail地址。
作为程序员拿到需求后,先做个简单的分析/拆解,理解真正要做的是什么,另:培养框架感
任务分析
- 取得文本
- 在文本中找出电话号码和E-mail
- 将找到的内容保存起来
对应着程序语言
1)复制粘贴功能
2)创建正则表达式:一个电话号码 和一个E-mail
3)将匹配的内容-按一定格式存放到字符串,方便复制
4)找不到相关的内容时 给出相应的提示
import re
phoneNumberRegex = re.compile(r'''(
(\d{3}|\(\d{3}\))? # area code
(\s|-|\.)? # separator
(\d{3}) # first 3 digits
(\s|-|\.) # separator
(\d{4}) # last 4 digits
(\s*(ext|x|ext.)\s*(\d{2,5}))? # extension
)''', re.VERBOSE | re.DOTALL)
emailRegex = re.compile(r'''(
[a-zA-Z0-9._%+-]+
@
[a-zA-Z0-9.-]+
(\.[a-zA-Z]{2,4})
)''', re.VERBOSE | re.DOTALL)
text = 'I am mary, my phone-number is 411-435-9999,my email address is qqin@126.com.cn hi ' \
'my phone-number is 412-222-4949,my email address is qingqian@sohu.com hihihi.'
matches = []
for phones in phoneNumberRegex.findall(text):
phoneNumber = '-'.join([phones[1],phones[3],phones[5]])
if phones[8] != '':
phoneNumber += ' x' + phones[8]
matches.append(phoneNumber)
for emails in emailRegex.findall(text):
matches.append(emails[0])
if len(matches) > 0:
print('\n'.join(matches))
else:
print('No phone numbers or email address found.')
运行结果:
411-435-9999
412-222-4949
qqin@126.com.cn
qingqian@sohu.com
所有学习都是从模仿开始的,本文照搬《Python编程快速上手-让繁琐工作自动化》