python3.5学习笔记(第六章)
本章内容:
正则表达式详解(re模块)
1、不使用正则表达式来查找文本的内容
要求从一个字符串中查找电话号码,并判断是否匹配制定的模式,如:555-555-5555。传统的查找方法如下:
def isPhoneNumber(text):
if len(text) != 12:
return False
for i in range(0,3):
if not text[i].isdecimal():
return False
if text[3] !='-':
return False
for i in range(4,7):
if not text[i].isdecimal():
return False
if text[7] !='-':
return False
for i in range(8,12):
if not text[i].isdecimal():
return False
return True message = "Call me at 415-232-2354 tomorrow. 415-234-2545 is my office."
for i in range(len(message)):
chunk = message[i:i+12]
if isPhoneNumber(chunk):
print('Phone number found:'+chunk)
print('Done')
>>>
Phone number found:415-232-2354
Phone number found:415-234-2545
Done
解析:在for循环的每一次迭代中,取自message的一段新的12个字符被赋值给变量chunk,将chunk传递给isPhoneNumber(),看是否符合电话号码的模式,如果符合就打印出这段文本。最终该循环遍历整个字符串。
2、用正则表达式查找文本模式
正则表达式,简称regex,是文本模式的描述方法。比如 \d\d\d-\d\d\d-\d\d\d\d 可以匹配 3个数字,一个短线,3个数字,一个短线,4个数字,也就是上面说的电话号码的格式。
在一个模式后面加上花括号包围的数字,比如 {3} ,就是说匹配这个模式3次。所以上面的 \d\d\d-\d\d\d-\d\d\d\d 可以表示为 \d{3}-\d{3}-\d{4} 。
2.1 创建正则表达式对象
python中的所有正则表达式的函数都在re模块中,使用前要先导入该模块。
import re
向 re.compile() 传入一个字符串,表示正则表达式,它将返回一个Regex模式对象。
phone_number_regex = re.compile(r'\d{3}-\d{3}-\d{4}')
2.2 匹配Regex对象
Regex对象的search()方法查找传入的字符串,寻找该正则表达式的所有匹配。如果没有找到,则返回None;如果找到了,则返回一个Match对象。Match对象有一个group()方法,它返回被查找字符串中实际匹配的文本。
import re
#正则表达式返回全部文本
phone_number_regex = re.compile(r'\d{3}-\d{3}-\d{4}') #{3}表示这个表达式匹配3次
mo = phone_number_regex.search('My number is 515-555-5555')
print('Phone number found:'+ mo.group()) #mo是一个Match对象,需要调用group()方法才会打印实际匹配到的文本
>>>
Phone number found:515-555-5555
2.3 正则表达式匹配小结
(1)用import re 导入正则表达式模块。
(2)用re.compile() 函数创建一个Regex对象(要使用原始字符串)。
(3)向Regex对象的search()方法传入想要查找的字符串,会返回一个Match对象。
(4)调用Match对象的group()方法,返回实际匹配文本的字符串。
3、用正则表达式匹配更多的模式
3.1 利用括号分组
添加括号将在正则表达式中创建分组没然后可以利用group方法从一个分组中获取匹配的文本。
在正则表达式中,第一对括号是第一组,第二对括号是第二组。向group传入参数1或2,就可以取得匹配到的文本中的不同部分(分组),向group传入参数0或者不传入参数,将会取得匹配到的文本的全部内容。
import re
phone_number_regex = re.compile(r'(\d{3})-(\d{3}-\d{4})')
mo = phone_number_regex.search('My number is 515-555-5555')
print('Phone number found:'+ mo.group(1))
>>>Phone number found:515
如果想要一次获得全部的分组,可以使用groups方法
import re
phone_number_regex = re.compile(r'(\d{3})-(\d{3}-\d{4})')
mo = phone_number_regex.search('My number is 515-555-5555')
g_1 ,g_2 = mo.groups()
print('g_1:',g_1)
print('g_2:',g_2)
>>>
g_1: 515
g_2: 555-5555
因为括号在正则表达式中默认用于分组,所以想要匹配真正的括号时需要对括号进行转义(两边都要转义)
import re
phone_number_regex = re.compile(r'(\(\d{3}\)) (\d{3}-\d{4})')
mo = phone_number_regex.search('My number is (515) 555-5555')
print('Phone number found:'+ mo.group(1))
>>>
Phone number found:(515)
3.2 用管道匹配多个分组
希望匹配多个表达式中的一个时,可以使用管道符 ‘|’ ,如果希望匹配的文本都出现在了被查找的字符串中,那么第一次出现的匹配文本将会作为Match对象被返回。
import re
hero_regex = re.compile(r'Batman|Tina Fey')
mo = hero_regex.search('Batman and Tina Fey')
print(mo.group())
>>>
Batman
也可以通过指定前缀和管道符组合,实现多个表达式的匹配。
import re
bat_regex = re.compile(r'Bat(man|mobile|copter|bat)') #Bat是前缀,与括号中内容进行组合。
mo1 = bat_regex.search('Batmobile lost a wheel')
print(mo1.group()) #返回完全匹配的文本
print(mo1.group(1)) #返回括号分组内匹配的文本
>>>
Batmobile
mobile
3.3 用问号实现可选匹配
字符 ?表示它前面的表达式或分组在这个模式中是可选的。但是?只匹配零次或一次。
import re
bat_Regex = re.compile(r'Bat(wo)?man')
mo_1 = bat_Regex.search('The Adventures of Batman')
mo_2 = bat_Regex.search('The Adventures of Batwoman')
mo_3 = bat_Regex.search('The Adventures of Batwowoman')
print(mo_1.group())
print(mo_2.group())
print(mo_3)
>>>
Batman
Batwoman
None
3.4 用星号 * 匹配零次或多次
星号 * 的匹配方式与 ?有所不同,星号 * 可以匹配多次即只要存在就可以匹配。
import re
bat_Regex = re.compile(r'Bat(wo)*man')
mo_1 = bat_Regex.search('The Adventures of Batwowowoman')
print(mo_1.group())
>>>
Batwowowoman
3.5 用加号 + 匹配一次或多次(至少匹配到一次)
import re
bat_Regex = re.compile(r'Bat(wo)+man')
mo_1 = bat_Regex.search('The Adventures of Batman')
mo_2 = bat_Regex.search('The Adventures of Batwoman')
mo_3 = bat_Regex.search('The Adventures of Batwowoman')
print(mo_1)
print(mo_2.group())
print(mo_3.group())
>>>
None
Batwoman
Batwowoman
3.6 用花括号匹配特定的次数
如果想要一个分组重复特定次数,就在正则表达式中该分组的后面,跟上一个花括号,括号中的数字表示重复的次数。如
phone_number_regex = re.compile(r'\d{3}-\d{3}-\d{4}')
除了制定一个数字,还可以制定一个范围,即在花括号后面写一个最小值a,一个最大值b,如{a,b}。
正则表达式{Ha}{3,5} 将匹配 ‘HaHaHa’、‘HaHaHaHa’ 和 ‘HaHaHaHaHa’ 。也可以省略第一个或者第二个数字,不限定最小值或最大值。
import re
ha_regex_1 = re.compile(r"(ha){3}")
m_1 = ha_regex_1.search('hahahaha')
print(m_1.group())
ha_regex_2 = re.compile(r'(ha){3,5}') #匹配3-5次,返回尽可能多的文本(贪心匹配)
m_2 = ha_regex_2.search('hahahahahaha')
print(m_2.group())
>>>
hahaha
hahahahaha
4、贪心和非贪心匹配
python的正则表达式默认是在有多种匹配结果的情况下,尽可能匹配最长的字符串。如果需要尽可能匹配最短的字符串,在花括号后面添加一个问号 ? 即可
import re
ha_regex_1 = re.compile(r'(ha){3,5}') #匹配3-5次,返回尽可能多的文本(贪心匹配)
m_1 = ha_regex_1.search('hahahahahaha')
print(m_1.group())
ha_regex_2 = re.compile(r'(ha){3,5}?') #匹配3-5次,返回尽可能多的文本(贪心匹配)
m_2 = ha_regex_2.search('hahahahahaha')
print(m_2.group())
>>>
hahahahaha
hahaha
注意: 问号在python中有两种含义:一种是表示匹配可选分组,另一种是声明非贪心匹配,要注意区分。
5、findall() 方法
search方法将返回被查找字符串中第一次匹配到的文本,而findall方法将返回被查找字符串中的匹配到的所有文本,findall返回的不是Match对象,而是一个字符串列表。
import re
phone_numbre_regex = re.compile(r'\d{3}-\d{3}-\d{4}')
phone_number = phone_numbre_regex.findall('Cell:555-555-5555 Work:888-888-8888')
print(phone_number)
>>>
['555-555-5555', '888-888-8888']
如果正则表达式中有分组,则返回元组的列表。
import re
phone_numbre_regex = re.compile(r'(\d{3})-(\d{3}-\d{4})')
phone_number = phone_numbre_regex.findall('Cell:555-555-5555 Work:888-888-8888')
print(phone_number)
>>>
[('', '555-5555'), ('', '888-8888')]
6、字符分类
常用字符分类的缩写代码
缩写字符分类 |
表示 |
\d | 0-9的任何数字 |
\D | 除0-9数字以外的任何字符 |
\w | 任何字母、数字、下划线字符(可以认为是匹配‘单词’字符) |
\W | 除字母、数字和下划线以外的任何字符 |
\s | 空格、制表符或换行符(可以认为是匹配‘空白’)字符 |
\S | 除空格、制表符和换行符之外的任何字符 |
7、建立自己的字符分类
可以用方括号 [ ] 建立自己的字符分类,比如[aeiouAEIOU]将匹配所有的元音字母,不论大小写。
import re
vowelregex = re.compile(r'[aeiouAEIOU]')
str_1 = vowelregex.findall('hsoaiejdpoaJEP WGEPAEF JFOPAWJE[oeofjgjop jfgawpe')
print(str_1)
也可以使用短横线表示字母或者数字的范围,比如字符分类[0-9a-zA-Z]将匹配所有的数字和大小写字母。
import re
vowelregex = re.compile(r'[0-9a-zA-Z]')
str_1 = vowelregex.findall('hlsijrg894w4t23\.wsew213^&*%^&$79832hiu we')
print(str_1)
注意在方括号中,普通的正则表达式符号均代表原本的意义,不需要进行转义。
通过在字符分类的左方括号右边添加一个插入字符 ^ ,就可以得到“非字符类”,也就是说正则表达式将匹配不在这个字符分类中的字符。
import re
vowelregex = re.compile(r'[^aeiouAEIOU]')
str_1 = vowelregex.findall('hsoaiej WGEPAEF JFJE[oeoop jfgawpe')
print(str_1)
8、插入字符和美元字符
可以在正则表达式的开始处使用插入字符^,表示匹配必须发生在被查找文本的开始处;
import re
begin = re.compile(r'^hello')
answer_1 = begin.search('hello world')
answer_2 = begin.search('world hello')
print(answer_1.group())
print(answer_2)
>>>
hello
None
同样,也可以在正则表达式的末尾添加一个美元字符$,表示该字符串必须以这个正则表达式的模式结束。
import re
begin = re.compile(r'hello$')
answer_1 = begin.search('hello world')
answer_2 = begin.search('world hello')
print(answer_1)
print(answer_2.group())
>>>
None
hello
可以同时使用插入符和美元字符,表示整个字符串必须匹配该模式,而不是只匹配其中的子集。
import re
begin = re.compile(r'^hello$')
answer_1 = begin.search('hello')
answer_2 = begin.search('world hello')
print(answer_1.group())
print(answer_2)
>>>
hello
None
9、通配字符
句点 . 被称为“通配符” 。它匹配除换行符之外的所有字符。但是句点只能匹配一个字符,比如r'.s' 只能匹配到 ‘us’,而不能匹配‘yours’。
import re
begin = re.compile(r'.')
answer_1 = begin.search('hello')
print(answer_1.group())
>>>
h
9.1 用点-星(.*)匹配所有的字符串,点-星表示任意文本。
import re
begin = re.compile(r'.*')
answer_1 = begin.search('hello')
print(answer_1.group())
>>>
hello
9.2 用句点字符匹配换行
如果想要用点-星匹配包括换行符在内的所有字符,可以通过给compile传入第二个参数re.DOTALL实现。
import re
begin = re.compile(r'.*',re.DOTALL)
answer_1 = begin.search('hello \nworld')
print(answer_1.group())
>>>
hello
world
10、正则表达式常用符号
? | 匹配零次或一次前面的分组 |
* | 匹配零次或多次前面的分组 |
+ | 匹配一次或多次前面的分组 |
{n} | 匹配n次前面的分组 |
{n,} | 匹配n次或更多次前面的分组 |
{,m} | 匹配零次到m次前面的分组 |
{n,m} | 匹配至少n次,至多m次前面的分组 |
{n,m}?或*?或+? | 对前面的分组进行非贪心匹配 |
^spam | 字符串必须以spam开始 |
spam$ | 字符串必须以spam结束 |
. | 匹配除换行符之外的所有字符 |
\d,\w,\s | 分别匹配数字、字母和空格 |
\D,\W,\S | 分别匹配除数字、字母和空格之外的所有字符 |
[abc] | 匹配方括号内的任意字符 |
[^abc] | 匹配不在方括号内的任意字符 |
11、不区分大小写的匹配
一般来说,正则表达式是区分大小写的,如果想要正则表达式不区分大小写,可以向re.compile()中传入re.I作为第二个参数。
import re
begin = re.compile(r'[a-z]*',re.I)
answer_1 = begin.search('ahisdhfliNILSHILHAI')
print(answer_1.group())
>>>
ahisdhfliNILSHILHAI
12、用sub()方法替换字符串
regex对象的sub方法需要传入两个参数,第一个参数是一个字符串,用于取代发现的匹配。第二个参数是一个字符串,是用正则表达式匹配的内容。sub方法返回替换完成后的字符串。
import re
name_regex = re.compile(r'world')
answer_1= name_regex.sub('小姐姐','hello world')
print(answer_1)
>>>
hello 小姐姐
13、管理复杂的正则表达式
通常正则表达式写成一段会很难阅读,所以可以将正则表达式写成多行字符串的形式,用三个引号括起来,同时向re.compile()中传入参数re.VERBOSE 告诉compile 忽略表达式中的空白符和注释。
import re
name_regex = re.compile(r'''
(\d{3}) #匹配三个数字
(.{3}) #匹配除换行符之外的任意内容三次
(\w{3}) #匹配三个字母
''',re.VERBOSE)
answer_1= name_regex.search('555w*whello world')
print(answer_1.group())
>>>
555w*whel
14、组合使用re.I 、re.DOTALL、re.VERBOSE
re.compile()只接受两个参数,如果希望在使用re.I忽略大小写时,同时让句点可以匹配换行符,或者可以在表达式中添加注释,可以用管道符将这些参数合并起来。
regex = re.compile(r'[a-z]',re.I|re.DOTALL|re.VERBOSE)
import re
name_regex = re.compile(r'''
([a-z]*) #匹配任意多个字母,不区分大小写
(\n) #匹配一个换行符
([0-9]*) # 匹配任意多个数字
''',re.I|re.DOTALL|re.VERBOSE)
answer_1= name_regex.search('abcdABCD\n8097809')
print(answer_1.group())
>>>
abcdABCD
8097809
python3.5学习笔记(第六章)的更多相关文章
- python3.4学习笔记(十六) windows下面安装easy_install和pip教程
python3.4学习笔记(十六) windows下面安装easy_install和pip教程 easy_install和pip都是用来下载安装Python一个公共资源库PyPI的相关资源包的 首先安 ...
- JVM学习笔记-第六章-类文件结构
JVM学习笔记-第六章-类文件结构 6.3 Class类文件的结构 本章中,笔者只是通俗地将任意一个有效的类或接口锁应当满足的格式称为"Class文件格式",实际上它完全不需要以磁 ...
- C Primer Plus 学习笔记 -- 前六章
记录自己学习C Primer Plus的学习笔记 第一章 C语言高效在于C语言通常是汇编语言才具有的微调控能力设计的一系列内部指令 C不是面向对象编程 编译器把源代码转化成中间代码,链接器把中间代码和 ...
- Linux学习笔记(第六章)
第六章-档案权限与目录配置#chgrp:改变档案的所属群组#chown:改变档案的拥有者#chmod:改变档案的权限及属性 chown用法 chmod用法: r:4 w:2 x:1对于文档: 对于目录 ...
- o'Reill的SVG精髓(第二版)学习笔记——第六章
第六章:坐标系统变换 想要旋转.缩放或者移动图片到新的位置.可以给对应的SVG元素添加transform属性. 6.1 translate变换 可以为<use>元素使用x和y属性,以在特性 ...
- 学习笔记 第六章 使用CSS美化图片
第六章 使用CSS美化图片 6.1 在网页中插入图片 GIF图像 跨平台能力,无兼容性问题: 具有减少颜色显示数目而极度压缩文件的能力,不会降低图像的品质(无损压缩): 支持背景透明功能,便于图像 ...
- [Python学习笔记][第六章Python面向对象程序设计]
1月29日学习内容 Python面向对象程序设计 类的定义与使用 类定义语法 使用class关键词 class Car: def infor(self): print("This is ca ...
- Java 学习笔记 ------第六章 继承与多态
本章学习目标: 了解继承的目的 了解继承与多态的关系 知道如何重新定义方法 认识java.lang.object 简介垃圾回收机制 一.继承 继承是java面向对象编程技术的一块基石,因为它允许创建分 ...
- 《Python基础教程(第二版)》学习笔记 -> 第六章 抽象
抽象和结构 本章将会介绍如何让将语句组织成函数,还会详细介绍参数(parameter)和作用域(scope)的概念,以及递归的概念及其在程序中的用途. 创建函数 函数可以调用,它执行某种行为,并返回某 ...
- Python3.6学习笔记(六)
WSGI Python Web Server Gateway Interface 规范学习 由于Python的灵活性,提供了多种方式可以作为服务端语言,包括Python编写的服务器(Medusa).P ...
随机推荐
- 零元学Expression Blend 4 - Chapter 45 ListBox里的物件不能换行吗?
原文:零元学Expression Blend 4 - Chapter 45 ListBox里的物件不能换行吗? ListBox里的排列不是垂直就是水平,觉得这样的排列很枯燥乏味吗? 想要它变聪明吗? ...
- 零元学Expression Blend 4 - Chapter 3 熟悉操作第一步(制作一个猴子脸)
原文:零元学Expression Blend 4 - Chapter 3 熟悉操作第一步(制作一个猴子脸) 本篇内容会教你如何使用笔刷.钢笔.渐层以及透明度的调整,还有如何转化图层和路径,最重要的是要 ...
- 安卓ImageButton圆角按钮设置
首先图片要做成圆角的,使用美图秀秀,这个不多说. 之后使用设置了圆角的按钮,效果有缺陷,按钮会有灰色的边角. 类似这样: 去掉的方法是将layout的 android:src="@draw ...
- [VS]VS2017 安装ReportDesigner/ReportViewer的方法
原文:[VS]VS2017 安装ReportDesigner/ReportViewer的方法 解决安装完VS2017后,无法用ReportDesigner/ReportViewer打开.rdlc文件V ...
- Qt 使用 Google Breakpad 捕获程序崩溃报告(dump文件) good
http://blog.csdn.net/GoForwardToStep/article/details/56685810
- 解决C/C++程序执行一闪而过的方法(使用getchar,或者cin.get,不推荐system(“pause”))
简述 在VS编写控制台程序的时候,包括使用其他IDE(Visual C++)编写C/C++程序,经常会看到程序的执行结果一闪而过,要解决这个问题,可以在代码的最后加上system(“pause”).g ...
- 面向对象编程(Object Oriented Programming,OOP,面向对象程序设计)
一.概述 面向过程:根据业务逻辑从上到下写代码 函数式:将具有一些功能的代码封装到函数中,需要的时候调用即可 面向对象:对函数进行分类和封装,让开发更方便,更快捷 Java和C#只支持面型对象编程,, ...
- java中的String、StringBuffer、StringBuilder的区别
java中String.StringBuffer.StringBuilder是编程中经常使用的字符串类,他们之间的区别也是经常在面试中会问到的问题.现在总结一下,看看他们的不同与相同. 1.可变与不可 ...
- Django之分页器组件
class Pagination(object): def __init__(self,current_page,all_count,per_page_num=2,pager_count=11): & ...
- kubernetes实战篇之helm使用技巧
系列目录 使用压缩包安装chart 我们使用helm package打包的时候,默认会在当前位置生成一个tgz压缩包,然后helm把它复制到到$HOME/.helm/repository目录下,现在还 ...