文档章节

Python核心编程:第15章

finndai
 finndai
发布于 2016/11/28 21:57
字数 3577
阅读 11
收藏 1

15.1    正则表达式为高级文本模式匹配,以及搜索-替代等功能提供了基础。正则表达式(RE)是一些由字符和特殊符号组成的字符串,它们描述了这些字符和字符的某种重复方式,因此能按某种模式匹配一个有相似特征的字符串的集合,因此能按某模式匹配一系列有相似特征的字符串。

            搜索与匹配:搜索,即在字符串任意部分中搜索匹配的模式,而匹配是指,判断一个字符串能否从起始处全部或部分的匹配某个模式

15.2 正则表达式使用的特殊符号和字符

            15.2.1 用管道符号(|)匹配多个正则表达式模式

                    (|)表示一个或的操作

                        正则表达式模式         匹配的字符串

                    at|home                        at,home

                    r2d2|c3po                     red2, c3po

            15.2.2 匹配任意一个单个的字符(.)

                        点字符或句点(.)符号匹配除换行符外的任意一个单个字符。

            15.2.3 从字符串的开头或结尾或单词边界开始匹配(^/$/\b/\B)

            15.2.4 创建字符类([])

                     正则表达式模式     配的字符串

                    [cr] [23] [dp] [o2]    可以为c2d2,r3po,.......

              15.2.5 指定范围(-)和否定(^)

                      正则表达式模式      匹配的字符

                      z.[0-9]                     字符z,后面跟任意一个字符

                      [^aeiou]                  一个非元音字符

              15.2.6 使用闭包操作符(*,+,?,{})实现多次出现/重复匹配

                      星号或称星号操作符匹配它左边那个正则表达式出现0次或0次以上的情况

                      加号操作符匹配它左边那个正则表达式至少出现一次的情况

                       问号操作符匹配它左边那个正则表达式出现零次或一次的情况

                        花括号操作符里可以是单一的值,也可以是由逗号分开的一对值,如果是一个值,则表示匹配N次出现,如果

是一对值,如{M,N}就表示匹配M次到N次出现

                    正则表达式模式         匹配的字符

             [dn]ot?                                            d 或n 后面可接t,可不接

              0?[1-9]                                            可以有0,可以无0

                [0-9]{15,16}                                    15位或16位数字表示,如信用卡号码

                </?[^>]>+>                                    匹配所有的合法的HTML标签的字符串

                15.2.7 特殊字符表示,字符集

                      正则表达式模式          匹配的字符串

            \w+-\d+                                                  由一个字母或数字组成的字符串和至少一个数字,两部分中间由连字符连接

            [A-Za-z]\w*                                             第一个字符是字母,其余字符(如果有)是字母或者数字

            \d{3}-\d(3)-\d(4)                                    电话号码

            \w+@\w+\.com                                    简单的邮件地址

                15.2.8 用圆括号(())组建组

                    对正则表达式进行分组,如,你需要两个不同的正则表达式去比较一个字符串,另一个理由是为整个正则表达式添加一个重复操作符

                    正则表达式模式                                        匹配的字符串

                    \d+(\.\d*)?                                          表示简单的浮点数,即,任意个十进制数字,后面跟一个可选的小数点,然后再接0或者多个十进制数字

                    (Mr?s?\. )?[A-Z][a-z]* [ A-Za-z-]+       名字和姓氏,对名字的限制(首字母大写,其它字 母(如果存在)小写), 姓氏没有什么限制,允许有多个单词、横线、大写字母

15.3 正则表达式和Python语言

        15.3.1 re模块:核心函数和方法

                  compile()函数、match()函数、search()函数

        15.3.2 使用compile()编译正则表达式

                    编译

        15.3.3匹配对象和group()、groups()方法

                    group()方法或者返回所有匹配对象或是根据要求返回某个特定子组

                    groups()返回一个包含全部匹配的子组的元组

        15.3.4用match()匹配字符串

                    match()函数尝试从字符串的开头开始对模式进行匹配,如果匹配成功,就返回一个匹配对象,如果匹配失败,就返回None

import re
m=re.match('foo','foo')
if m is not None:
	print m.group()
	

                   如果字符串比较长,匹配也可能成功

                如:re.match('foo','food on the table').group()

    15.3.5 search()在一个字符串中查找一个模式

               search()查找字符串中模式首次出现的位置,而不是尝试在起始处匹配。严格的说,search是从左到右进行搜索的。

            

import re
m=re.search('foo','testfoo')
if m is not None:
	print m.group()
	

    15.3.6 匹配任意多个字符串 (|)            

               相当于或,用match匹配,search查找

    15.3.7 匹配任意单个字符(.)

                不能匹配非字符(如空字符串)和换行符,空格是可以匹配的

    如    anyend = .end

            m=re.match('anyend','\nend')

    15.3.8 创建字符集和([ ])

    15.3.9重复、特殊字符和子组

import re
patt = '\w+@(\w+\.)?\w+\.com'
print re.match(patt,'dxf@ly.com').group()

m = re.match('\w\w\w-\d\d\d','abc-123')

m1 = re.match('(\w\w\w)-(\d\d\d)','abc-123')

print m1.group()
print m1.group(1)
print m1.group(2)
print m1.groups()

    15.3.10 从字符串的开头或结尾匹配及在单词边界上的匹配

                    主要用于search()

            m = re.search('^The','The end')

            m= re.search('\bthe','bite the dog')

    15.3.11 用findall()找到每个出现的匹配部分

               findall()和search()相似之处在于两者都执行字符串搜索,但findall()和match()与search()不同之处是,findall总返回一个列表

    

import re
m = re.findall('car','carry the barcardi to the car')
print m

 

    15.3.12 用sub()(和sub())进行搜索和替换

  有两种函数/方法用于完成搜索和代替的功能:sub() 和subn()。二者几乎一样,都是将某字符串中所有匹配正则表达式模式的部分进行替换。用来替换的部分通常是一个字符串,但也可能是

一个函数,该函数返回一个用来替换的字符串。subn()和sub()一样,但它还返回一个表示替换次数的数字,替换后的字符串和表示替换次数的数字作为一个元组的元素返回。

import re
m=re.sub('X','Mr. Simth','attn: X\n\nDear X,\n')
print m

m1=re.subn('X', 'Mr. Simth', 'attn: X\n\nDear X,\n')
print m1

 

    15.3.13 用split()分割(分割模式)

      re模块和正则表达式对象的方法split()与字符串的split()方法相似

       re模块和正则表达式对象的方法split()与字符串的split()方法相似,前者是根据正则表达式模式分离字符串,后者是根据固定的字符串分离,因此与后者相比,显著提升了字符分割的能力

同时可以设置最大分割次数

            re.split(':', 'str1:str2:str3')

    15.4正则表达式示例

·            

from random import randint,choice
from string import lowercase
from sys import maxint
from time import ctime

doms = ('com','edu','net','org','gov')

for i in range(randint(5,10)):
	dtint = randint(0,maxint-1)
	
	dtstr = ctime(dtint)
	
	shorter=randint(4,7)
	em = ''
	for j in range(shorter):
	
		em += choice(lowercase)
		
	longer = randint(shorter,12)
	dn = ''
	
	for j in range (longer):
	
		dn += choice(lowercase)
		
	print '%s::%s@%s.%s::%d-%d-%d' %(dtstr, em,dn,choice(doms),dtint,shorter,longer)
	

 

        15.4.2 搜索与匹配的比较,贪婪匹配

            “.+”表示任意个字符集,会默认抓取满足匹配的最长字符串

               解决“非贪婪”的操作符“?”,这个操作符可以用在“*”,“+”,或”?“的后面,它的作用是要求正则表达式引擎匹配的字符越少越好

  15.5 练习

        15-1识别下列字符串:“bat,” “bit,” “but,” “hat,” “hit,” 或 “hut”

import re
patt='bat|bit||but|hat|hit|hut|'
m = re.match(patt,'bit')
print m.group()

         15-2 匹配用一个空格分隔的任意一对单词,比如,名和姓。

import re
patt='\w+\s\w+'
m = re.match(patt,'lin feng')
print m.group()

        15–3. 匹配用一个逗号和一个空格分开的一个单词和一个字母。例如,英文人名中的姓和名的首字母。 

import re
patt='\w+\,\s[a-zA-Z]'
m = re.match(patt,'dai, f')
print m.group()

      15-4 匹配所有合法的Python 标识符。

import re
patt='([A-Za-z_]+)([A-Za-z0-9_]*)'
m = re.match(patt,'d_333f')
print m.group()

      15-5 请根据您(读者)本地关于地址的格式写法匹配一个街道地址(你写出的正则表达式要尽可能通用以匹配任意数目的表示街道名字的单词,包括类型指示)。比如,美国的街道地址使用这样的格式:1180 Bordeaux Drive. 使你写的正则表达式尽可能通用,要求能够匹配多个单词的街道名字,如:3120 De la Cruz Boulevard.

import re
patt='\d+(\s[a-zA-Z]+)+'
m = re.match(patt,'3120 De la Cruz Boulevard')
print m.group()

15–6. 匹配简单的以“www.”开头,以“.com”作结尾的Web 域名,例如:www.yahoo.com. 附加题:使你写的正则表达式还支持其他顶级域名:.edu, .net 等,比如:www.ucsc.edu.

import re
patt='(www\.)(\w+)\.[com|edu|net]*'
m = re.match(patt,'www.yahoo.com')
print m.group()

15-7匹配全体Python整数的字符串表示形式的集合

patt ='\d+'

15-8  匹配全体Python长整数的字符串表示形式的集合

patt='\d+[1L]'

15-9  匹配全体Python浮点数的字符串表示形式的集合

patt = '\d+\.\d*'

15-10 匹配全体Python复数的字符串表示形式的集合

import re
patt='(\d*\.?\d*)([+-])?(\d*\.?\d*)j'
m = re.match(patt,'2.5+4j')
print m.group()

15-11 匹配所有合法的电子邮件地址(先写出一个限制比较宽松的正则表达式,然后尽可能加强限制条件,但要保证功能的正确性)。

import re
patt='\w+@\w+.com'
m = re.match(patt,'finndai@163.com')
print m.group()

15-12.匹配所有合法的Web网站地址(URLs)(先写出一个限制比较宽松的正则表达式,然后尽可能加强限制条件,但要保证功能的正确性)。

import re
patt='www\.\w+\.\w+'
m = re.match(patt,'www.google.com')
print m.group()

15-13type(). type()内建函数返回一个对象类型,此对象显示为Python 的字符串形式,
如下所示:
>>> type(0)
<type 'int'>
>>> type(.34)
<type 'float'>
>>> type(dir)
<type 'builtin_function_or_method'>
请写一个正则表达式,能从这个字符串中提取出类型的名字。

import re
ret = type(dir)
patt="<type '(\w+)'>"
m = re.search(patt,str(ret))
print m.group(1)

15-14正则表达式。在15.2小节里,我们给出一个匹配由一位或两位数字代表一月到九月的字符串形式(“0?[1-9]”)。请写出一个正则表达式表示标准日历上其它的三个月(十月、十一月、十二月)。

   patt='1[0-2]'

15–15. 正则表达式。在15.2 小节里,我们给出一个匹配信用卡卡号的模式:(“[0-9]{15,16}”).但这个模式不允许用连字符号分割信用卡卡号中的数字。请写出一个允许使用连字符的正则表达式,但要求连字符必须出现在正确的位置。例如,15 位的信用卡卡号的格式是4-6-5,表示四个数字,一个连字符,后面接六个数字、一个连字符,最后是五个数字。16 位的信用卡卡号的格式是4-4-4-4,数位不足时,添0 补位。附加题:有一个用于确定某个信用卡卡号是否合法的算法。请写一段代码,它不但能识别格式正确的信用卡卡号,还能验证它的有效性。

import re
patt='[0-9]{4}-[0-9]{6}-[0-9]{5}|[0-9]{4}-[0-9]{4}-[0-9]{4}'
m = re.match(patt,'6555-4444-3333')
print m.group()

15–16. 修改脚本gendata.py 的代码,使数据直接写入文件redata.txt 中,而不是输出到屏幕上。

from random import randint,choice
from string import lowercase
from sys import maxint
from time import ctime

doms = ('com','edu','net','org','gov')
f=open('redata.txt','w+')

for i in range(randint(5,10)):
	dtint = randint(0,maxint-1)
	
	dtstr = ctime(dtint)
	
	shorter=randint(4,7)
	em = ''
	for j in range(shorter):
	
		em += choice(lowercase)
		
	longer = randint(shorter,12)
	dn = ''
	
	for j in range (longer):
	
		dn += choice(lowercase)
		
	f.write ('%s::%s@%s.%s::%d-%d-%d' %(dtstr, em,dn,choice(doms),dtint,shorter,longer))
f.close()

15-17. 统计生成的redata.txt 文件中,星期中的每一天出现的次数(或统计各月份出现的次数)。 

import re
patt='(Mon|Tue|Wed|Thu|Fri|Sat|Sun)+'
num=[]
with open ('redata.txt') as f:
	for item in f:
		num += re.findall(patt,item)
		
print "Mon:%d" %num.count("Mon")
print "Tue:%d" %num.count("Tue")
print "Wed:%d" %num.count("Wed")
print "Thu:%d" %num.count("Thu")
print "Fri:%d" %num.count("Fri")
print "Sat:%d"  %num.count("Sat")
print "Sun:%d" %num.count("Sun")

15-19提取出每行中完整的时间戳字段。

import re 
patt ='[a-zA-Z]+ [a-zA-Z]+ \d+ \d+:\d+:\d+ \d+'
num = []
with open ('redata.txt') as f:
	for item in f:
		num += re.findall(patt,item)
print num

15-20 提取出每行中完整的电子邮件地址。

import re 
patt ='\w+@\w+\.[com|edu|net|org|gov]+'
num = []
with open ('redata.txt') as f:
	for item in f:
		num += re.findall(patt,item)
print num

15.21 只提取出时间戳字段中的月份。

import re 
patt ='[a-zA-Z]+ [a-zA-Z]+ \d+ \d+:\d+:\d+ \d+'
num = []
with open ('redata.txt') as f:
	for item in f:
		num += re.findall(patt,item)
for item in num:		
	print item.split(' ')[1]

15-22. 只提取出时间戳字段中的年份。

import re 
patt ='[a-zA-Z]+ [a-zA-Z]+ \d+ \d+:\d+:\d+ \d+'
num = []
with open ('redata.txt') as f:
	for item in f:
		num += re.findall(patt,item)
for item in num:		
	print item.split(' ')[4]

15-23只提取出时间戳字段中的值(格式:HH:MM:SS)。

import re 
patt ='[a-zA-Z]+ [a-zA-Z]+ \d+ \d+:\d+:\d+ \d+'
num = []
with open ('redata.txt') as f:
	for item in f:
		num += re.findall(patt,item)
for item in num:		
	print item.split(' ')[3]

15-24 只从电子邮件地址中提取出登录名和域名(包括主域名和顶级域名,二者连在一起)。

import re 
patt ='\w+@\w+'
num = []
with open ('redata.txt') as f:
	for item in f:
		num += re.findall(patt,item)
print num
for item in num:
	print item.split('@')

15-25 只从电子邮件地址中提取出登录名和域名(包括主域名和顶级域名,二者分别提取)。

import re 
patt ='\w+@\w+'
num = []
with open ('redata.txt') as f:
	for item in f:
		num += re.findall(patt,item)
print num
for item in num:
	print item.split('@')[0],item.split('@')[1]
	

15–26. 将每行中的电子邮件地址替换为你自己的电子邮件地址。

import re 
patt ='\w+@\w+\.\w+'
num = []
with open ('redata.txt') as f:
	for item in f:
		num.append(re.sub(re.findall(patt,item)[0],'finndai@163.com',item))

with open ('redata.txt','w') as f:
	for item in num:
		f.write(item)

with open("redata.txt") as f:
	for line in f:
		print line

15-28区号(第一组的三个数字和它后面的连字符)是可选的,即,你写的正则表达式对800-555-1212 和555-1212 都可以匹配。

import re 
patt ='(\d{3}-)*\d{3}-\d{4}'
m = re.match(patt,'800-555-1212')
print m.group()

15-29 区号中可以包含圆括号或连字符,而且它们是可选的,就是说你写的正则表达式可以匹配800-555-1212、555-1212或(800)555-1212

写的有问题。。。

© 著作权归作者所有

共有 人打赏支持
finndai
粉丝 1
博文 35
码字总数 38131
作品 0
南京
私信 提问
那些年,我们读过的python!

Python是一个强大、快速、易学、友好、开源的脚本语言。Hacker必备的语言之一。 Python - 历史由来 Python 是一种开源的面向对象的脚本语言,它起源于1989年末,当时,CWI(阿姆斯特丹国家数...

生气的散人
2014/03/21
1K
2
买《Python从小白到大牛》专题视频课程,送配套纸质图书

经过一年多时间的呕心沥血,Python立体化图书——《Python从小白到大牛》即将与大家见面了。所谓立体化图书包括:电子图书、视频、课件和服务等内容。 《Python从小白到大牛》纸质图书将于9...

tony关东升
07/23
0
0
那些年,我们学过的编程语言——Python篇

Hello World!不少人都与这句话邂逅在大家最初学习编程的时候。 2014年12月的编程语言排行榜中,Python位列在众多语言中的第8位,一直保持在前列。初学者看着简单清晰的语言极其容易上手。即...

生气的散人
2014/12/26
1K
4
翻译:《用python和Qt进行GUI编程》——介绍

介绍: 这本书讲的是如何利用Python和Qt来开发GUI应用程序的。仅仅需要一点点必备的知识:你可以使用一些面相对象的语言来编程,例如C++,C#,java或者python等等。在富文本编辑的那些章节,...

duoduo3_69
2013/02/07
0
0
Python这么强大, 怎样才能快速入坑?

作为一种年轻的编程语言,Python为何能在短短几年的时间内就以迅雷不及掩耳之势驰骋编程界?答案很简单,在人工智能时代,AlphaGo 都在使用的 Python语言,是最接近 AI 的编程语言。 随着Pyt...

bodasisiter
08/23
0
0

没有更多内容

加载失败,请刷新页面

加载更多

etcd集群备份和数据恢复

etcd是一个分布式k-v数据库,在kubernetes中使用其管理集群的元数据。这里介绍etcd集群数据的备份和数据恢复的方法和步骤。 本文来自于:https://www.maideliang.com/index.php/archives/25/...

openthings
5分钟前
0
0
「阿里面试系列」面试加分项,从JVM层面了解线程的启动和停止

文章简介 这一篇主要围绕线程状态控制相关的操作分析线程的原理,比如线程的中断,线程的通信等,内容比较多,可能会分两篇文章 阿里面试系列导读:关注我的技术公众号【架构师修炼宝典】一周...

Java架构资源分享
12分钟前
1
0
centos安装confluence全攻略

https://blog.csdn.net/qwer026/article/details/51439076

happyeveryday32
25分钟前
3
0
30 行 Javascript 代码搞定智能家居系统

本文首发于『阿里云 IoT 开发者社区』,更多精彩物联网内容欢迎前往浏览。 智能家居可谓是今年物联网的热门领域,通过智能单品和智能音箱,人们已然把『智能』两个字变成了生活的理所应当。搭...

阿里云官方博客
28分钟前
4
0
sed插入和附加文本基础使用

对于编辑器来说,在数据中增加行算是很基本的操作吧,sed有以下两个操作: 插入(insert)命令(i)会在指定行前增加一个新行 附加(append)命令(a)会在指定行后增加一个新行 还是用下面的文本来测...

woshixin
36分钟前
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部