本章内容:

  正则表达式详解(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. 零元学Expression Blend 4 - Chapter 45 ListBox里的物件不能换行吗?

    原文:零元学Expression Blend 4 - Chapter 45 ListBox里的物件不能换行吗? ListBox里的排列不是垂直就是水平,觉得这样的排列很枯燥乏味吗? 想要它变聪明吗? ...

  2. 零元学Expression Blend 4 - Chapter 3 熟悉操作第一步(制作一个猴子脸)

    原文:零元学Expression Blend 4 - Chapter 3 熟悉操作第一步(制作一个猴子脸) 本篇内容会教你如何使用笔刷.钢笔.渐层以及透明度的调整,还有如何转化图层和路径,最重要的是要 ...

  3. 安卓ImageButton圆角按钮设置

    首先图片要做成圆角的,使用美图秀秀,这个不多说. 之后使用设置了圆角的按钮,效果有缺陷,按钮会有灰色的边角. 类似这样: 去掉的方法是将layout的  android:src="@draw ...

  4. [VS]VS2017 安装ReportDesigner/ReportViewer的方法

    原文:[VS]VS2017 安装ReportDesigner/ReportViewer的方法 解决安装完VS2017后,无法用ReportDesigner/ReportViewer打开.rdlc文件V ...

  5. Qt 使用 Google Breakpad 捕获程序崩溃报告(dump文件) good

    http://blog.csdn.net/GoForwardToStep/article/details/56685810

  6. 解决C/C++程序执行一闪而过的方法(使用getchar,或者cin.get,不推荐system(“pause”))

    简述 在VS编写控制台程序的时候,包括使用其他IDE(Visual C++)编写C/C++程序,经常会看到程序的执行结果一闪而过,要解决这个问题,可以在代码的最后加上system(“pause”).g ...

  7. 面向对象编程(Object Oriented Programming,OOP,面向对象程序设计)

    一.概述 面向过程:根据业务逻辑从上到下写代码 函数式:将具有一些功能的代码封装到函数中,需要的时候调用即可 面向对象:对函数进行分类和封装,让开发更方便,更快捷 Java和C#只支持面型对象编程,, ...

  8. java中的String、StringBuffer、StringBuilder的区别

    java中String.StringBuffer.StringBuilder是编程中经常使用的字符串类,他们之间的区别也是经常在面试中会问到的问题.现在总结一下,看看他们的不同与相同. 1.可变与不可 ...

  9. Django之分页器组件

    class Pagination(object): def __init__(self,current_page,all_count,per_page_num=2,pager_count=11): & ...

  10. kubernetes实战篇之helm使用技巧

    系列目录 使用压缩包安装chart 我们使用helm package打包的时候,默认会在当前位置生成一个tgz压缩包,然后helm把它复制到到$HOME/.helm/repository目录下,现在还 ...