本章内容:

  正则表达式详解(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学习笔记(第六章)的更多相关文章

  1. python3.4学习笔记(十六) windows下面安装easy_install和pip教程

    python3.4学习笔记(十六) windows下面安装easy_install和pip教程 easy_install和pip都是用来下载安装Python一个公共资源库PyPI的相关资源包的 首先安 ...

  2. JVM学习笔记-第六章-类文件结构

    JVM学习笔记-第六章-类文件结构 6.3 Class类文件的结构 本章中,笔者只是通俗地将任意一个有效的类或接口锁应当满足的格式称为"Class文件格式",实际上它完全不需要以磁 ...

  3. C Primer Plus 学习笔记 -- 前六章

    记录自己学习C Primer Plus的学习笔记 第一章 C语言高效在于C语言通常是汇编语言才具有的微调控能力设计的一系列内部指令 C不是面向对象编程 编译器把源代码转化成中间代码,链接器把中间代码和 ...

  4. Linux学习笔记(第六章)

    第六章-档案权限与目录配置#chgrp:改变档案的所属群组#chown:改变档案的拥有者#chmod:改变档案的权限及属性 chown用法 chmod用法: r:4 w:2 x:1对于文档: 对于目录 ...

  5. o'Reill的SVG精髓(第二版)学习笔记——第六章

    第六章:坐标系统变换 想要旋转.缩放或者移动图片到新的位置.可以给对应的SVG元素添加transform属性. 6.1 translate变换 可以为<use>元素使用x和y属性,以在特性 ...

  6. 学习笔记 第六章 使用CSS美化图片

    第六章  使用CSS美化图片 6.1  在网页中插入图片 GIF图像 跨平台能力,无兼容性问题: 具有减少颜色显示数目而极度压缩文件的能力,不会降低图像的品质(无损压缩): 支持背景透明功能,便于图像 ...

  7. [Python学习笔记][第六章Python面向对象程序设计]

    1月29日学习内容 Python面向对象程序设计 类的定义与使用 类定义语法 使用class关键词 class Car: def infor(self): print("This is ca ...

  8. Java 学习笔记 ------第六章 继承与多态

    本章学习目标: 了解继承的目的 了解继承与多态的关系 知道如何重新定义方法 认识java.lang.object 简介垃圾回收机制 一.继承 继承是java面向对象编程技术的一块基石,因为它允许创建分 ...

  9. 《Python基础教程(第二版)》学习笔记 -> 第六章 抽象

    抽象和结构 本章将会介绍如何让将语句组织成函数,还会详细介绍参数(parameter)和作用域(scope)的概念,以及递归的概念及其在程序中的用途. 创建函数 函数可以调用,它执行某种行为,并返回某 ...

  10. Python3.6学习笔记(六)

    WSGI Python Web Server Gateway Interface 规范学习 由于Python的灵活性,提供了多种方式可以作为服务端语言,包括Python编写的服务器(Medusa).P ...

随机推荐

  1. 如何线程调用C++类成员函数

    方法就是: 1,写成静态成员函数 2,参数为 (void* __this)用来传入类 对象指针(this) 3,进入函数首先    C类名 *_this = (C类名*)__this;  转化为对象指 ...

  2. 网站运行编译器错误CS1617: 选项“6”对 /langversion 无效;必须是 ISO-1、ISO-2、3、4、5 或 Default

    运行winform程序时提示, CS1617: 选项“6”对 /langversion 无效:必须是 ISO-1.ISO-2.3.4.5 或 Default 找到网站的web.config配置文件,找 ...

  3. Asp.Net MVC实现优酷(youku)Web的上传

    优酷第三方上传API没有.NET版本的SDK,让从事.NET开发人员要实现开放平台上传文件无从下手.本文经过一天的预读优酷文档,以NET方式实现了视频上传. 参考: 优酷开放文档 http://ope ...

  4. SQLite的使用(包括编译安装的步骤)

    SQLite官网http://www.sqlite.org/ SQLite简介 SQLite是一款轻型的数据库,是遵守ACID(原子性.一致性.隔离性和持久性)的关系式数据库管理系统.SQLite实现 ...

  5. QSocket 总体设计框架说明(观赏)

    QSocket 是 QDAC 开源组件的一个重要的组成部分,终于要开始开工了,为了方便大家了解 QSocket,对 QSocket 的总体设计的一些想法,我在这里给大家简要的描述一下. 首先,QSoc ...

  6. delphi xe5 中TMemo控件的应用——for android

    TMemo中的两个方法: TMemo.Lines.Add(stringxxx);意思是向TMemo中增加字符串stringxxx: TMemo.Lines.Text :=stringxxx,意思是清空 ...

  7. vi的替换使用、如何让linux有回收站功能、系统重要文件、目录数据

      1 vi的替换使用方法 vi使用的原理 (编辑文件会生成一个隐藏临时文件) 1.1 替换文件内容方法:vi (1)%s#oldboy#oldgirl#g --- 将oldboy全部替换为oldgi ...

  8. spring boot 2.x 系列 —— actuator 服务监控与管理

    文章目录 一.概念综述 1.1 端点 1.2 启用端点 1.3 暴露端点 1.4 健康检查信息 二.项目说明 1.1 项目结构说明 1.2 主要依赖 1.3 项目配置 1.4 查看监控状态 三.自定义 ...

  9. webpack打包工具的初级使用方法

    这里下载的是webpack的3.8.1版本(新版更新的使用有些问题) 什么是webpack? 他是一个前端资源加载或打包工具,. 资源: img css json等. 下载的话 用 npm webpa ...

  10. oh-my-zsh自定义配置

    oh-my-zsh主题配置 默认的zsh主题robbyrussell已经很棒了, 简洁高效, 能很好的显示git的相关信息, 比如branch信息, 修改, 删除, 添加等操作. 但是多用户的话就不能 ...