Python系列之正则表达式详解
Python 正则表达式模块 (re) 简介
Python 的 re 模块(Regular Expression 正则表达式)提供各种正则表达式的匹配操作,和 Perl 脚本的正则表达式功能类似,使用这一内嵌于 Python 的语言工具,尽管不能满足所有复杂的匹配情况,但足够在绝大多数情况下能够有效地实现对复杂字符串的分析并提取出相关信息。Python 会将正则表达式转化为字节码,利用 C 语言的匹配引擎进行深度优先的匹配。
表 1. 正则表达式元字符和语法
符号 | 说明 | 实例 |
---|---|---|
. | 表示任意字符,如果说指定了 DOTALL 的标识,就表示包括新行在内的所有字符。 | 'abc' >>>'a.c' >>>结果为:'abc' |
^ | 表示字符串开头。 | 'abc' >>>'^abc' >>>结果为:'abc' |
$ | 表示字符串结尾。 | 'abc' >>>'abc$' >>>结果为:'abc' |
*, +, ? | '*'表示匹配前一个字符重复 0 次到无限次,'+'表示匹配前一个字符重复 1次到无限次,'?'表示匹配前一个字符重复 0 次到1次 |
'abcccd' >>>'abc*' >>>结果为:'abccc' 'abcccd' >>>'abc+' >>>结果为:'abccc' 'abcccd' >>>'abc?' >>>结果为:'abc' |
*?, +?, ?? | 前面的*,+,?等都是贪婪匹配,也就是尽可能多匹配,后面加?号使其变成惰性匹配即非贪婪匹配 |
'abc' >>>'abc*?' >>>结果为:'ab' 'abc' >>>'abc??' >>>结果为:'ab' 'abc' >>>'abc+?' >>>结果为:'abc' |
{m} | 匹配前一个字符 m 次 | 'abcccd' >>>'abc{3}d' >>>结果为:'abcccd' |
{m,n} | 匹配前一个字符 m 到 n 次 | 'abcccd' >>> 'abc{2,3}d' >>>结果为:'abcccd' |
{m,n}? | 匹配前一个字符 m 到 n 次,并且取尽可能少的情况 | 'abccc' >>> 'abc{2,3}?' >>>结果为:'abcc' |
\ | 对特殊字符进行转义,或者是指定特殊序列 | 'a.c' >>>'a\.c' >>> 结果为: 'a.c' |
[] | 表示一个字符集,所有特殊字符在其都失去特殊意义,只有: ^ - ] \ 含有特殊含义 | 'abcd' >>>'a[bc]' >>>结果为:'ab' |
| | 或者,只匹配其中一个表达式 ,如果|没有被包括在()中,则它的范围是整个正则表达式 | 'abcd' >>>'abc|acd' >>>结果为:'abc' |
( … ) | 被括起来的表达式作为一个分组. findall 在有组的情况下只显示组的内容 | 'a123d' >>>'a(123)d' >>>结果为:'123' |
(?#...) | 注释,忽略括号内的内容 特殊构建不作为分组 | 'abc123' >>>'abc(?#fasd)123' >>>结果为:'abc123' |
(?= … ) | 表达式’…’之前的字符串,特殊构建不作为分组 | 在字符串’ pythonretest ’中 (?=test) 会匹配’ pythonre ’ |
(?!...) | 后面不跟表达式’…’的字符串,特殊构建不作为分组 | 如果’ pythonre ’后面不是字符串’ test ’,那么 (?!test) 会匹配’ pythonre ’ |
(?<= … ) | 跟在表达式’…’后面的字符串符合括号之后的正则表达式,特殊构建不作为分组 | 正则表达式’ (?<=abc)def ’会在’ abcdef ’中匹配’ def ’ |
(?:) | 取消优先打印分组的内容 | 'abc' >>>'(?:a)(b)' >>>结果为'[b]' |
?P<> | 指定Key | 'abc' >>>'(?P<n1>a)>>>结果为:groupdict{n1:a} |
表 2. 正则表达式特殊序列
特殊表达式序列 | 说明 |
---|---|
\A | 只在字符串开头进行匹配。 |
\b | 匹配位于开头或者结尾的空字符串 |
\B | 匹配不位于开头或者结尾的空字符串 |
\d | 匹配任意十进制数,相当于 [0-9] |
\D | 匹配任意非数字字符,相当于 [^0-9] |
\s | 匹配任意空白字符,相当于 [ \t\n\r\f\v] |
\S | 匹配任意非空白字符,相当于 [^ \t\n\r\f\v] |
\w | 匹配任意数字和字母,相当于 [a-zA-Z0-9_] |
\W | 匹配任意非数字和字母的字符,相当于 [^a-zA-Z0-9_] |
\Z | 只在字符串结尾进行匹配 |
上面提到贪婪匹配和非贪婪匹配请看例子:
import re
#贪婪
ret_greed= re.findall(r'a(\d+)','a23b')
print(ret_greed)
#非贪婪
ret_no_greed= re.findall(r'a(\d+?)','a23b')
print(ret_no_greed) ['23']
['2']
由于贪婪匹配为尽可能的多匹配所以结果为23 ,有人好奇了,findall是什么鬼 ,请耐心往下看:
re模块
正则表达式使用反斜杠” \ “来代表特殊形式或用作转义字符,这里跟Python的语法冲突,因此,Python用” \\ “表示正则表达式中的” \ “,因为正则表达式中如果要匹配” \ “,需要用\来转义,变成” \ “,而Python语法中又需要对字符串中每一个\进行转义,所以就变成了” \\ “。
上面的写法是不是觉得很麻烦,为了使正则表达式具有更好的可读性,Python特别设计了原始字符串(raw string),需要提醒你的是,在写文件路径的时候就不要使用raw string了,这里存在陷阱。raw string就是用’r’作为字符串的前缀,如 r”\n”:表示两个字符”\”和”n”,而不是换行符了。Python中写正则表达式时推荐使用这种形式。
1、 re.findall(pattern, string[, flags]):
方法能够以列表的形式返回能匹配的子串。先看简单的例子:
import re
a = 'one1two2three3four4'
ret = re.findall(r'(\d+)',a)
print(ret)
['1', '2', '3', '4']
从上面的例子可以看出返回的值是个列表,并且返回字符串中所有匹配的字符串。
2、re.finditer(pattern, string[, flags])
搜索string,返回一个顺序访问每一个匹配结果(Match对象)的迭代器。 请看例子:
import re p = re.compile(r'\d+')
for m in p.finditer('one1two2three3four4'):
print m.group(), ### output ###
# 1 2 3 4
3、re.match和re.search
Python提供了两种不同的原始操作:match和search。match是从字符串的起点开始做匹配,而search(perl默认)是从字符串做任意匹配。看个例子:
import re ret_match= re.match("c","abcde"); #从字符串开头匹配,匹配到返回match的对象,匹配不到返回None
if(ret_match):
print("ret_match:"+ret_match.group());
else:
print("ret_match:None"); ret_search = re.search("c","abcde"); #扫描整个字符串返回第一个匹配到的元素并结束,匹配不到返回None
if(ret_search):
print("ret_search:"+ret_search.group()); ret_match:None
ret_search:c
re.match对象拥有以下方法:
import re
a = "123abc456"
ret_match= re.match("a","abcde");
print(ret_match.group()) #返回返回被 RE 匹配的字符串
print(ret_match.start()) #返回匹配开始的位置
print(ret_match.end()) #返回匹配结束的位置
print(ret_match.span()) #返回一个元组包含匹配 (开始,结束) 的位置
其中group()方法可以指定组号,如果组号不存在则返回indexError异常看如下例子:
import re
a = "123abc456"
re.search("([0-9]*)([a-z]*)([0-9]*)",a).group(0) #123abc456,返回整体默认返回group(0)
re.search("([0-9]*)([a-z]*)([0-9]*)",a).group(1) #123
re.search("([0-9]*)([a-z]*)([0-9]*)",a).group(2) #abc
re.search("([0-9]*)([a-z]*)([0-9]*)",a).group(3) #456
4、re.sub和re.subn
两种方法都是用来替换匹配成功的字串,值得一提的时,sub不仅仅可以是字符串,也可以是函数。subn函数返回元组,看下面例子:
import re
#sub
ret_sub = re.sub(r'(one|two|three)','ok','one word two words three words') #ok word ok words ok words
#subn
import re
ret_subn = re.subn(r'(one|two|three)','ok','one word two words three words') #('ok word ok words ok words', 3) 3,表示替换的次数
5、re.split(pattern, string, maxsplit=0)
通过正则表达式将字符串分离。如果用括号将正则表达式括起来,那么匹配的字符串也会被列入到list中返回。maxsplit是分离的次数,maxsplit=1分离一次,默认为0,不限制次数。看一下例子:
import re
ret = re.split('\d+','one1two2three3four4') #匹配到1的时候结果为'one'和'two2three3four4',匹配到2的时候结果为'one', 'two'和'three3four4', 所以结果为:
####output####
['one', 'two', 'three', 'four', '']
6、re.compile(strPattern[, flag])
这个方法是Pattern类的工厂方法,用于将字符串形式的正则表达式编译为Pattern对象。第二个参数flag是匹配模式,取值可以使用按位或运算符’|’表示同时生效,比如re.I | re.M。另外,你也可以在regex字符串中指定模式,比如re.compile(‘pattern’, re.I | re.M)与re.compile(‘(?im)pattern’)是等价的。可选值有:
re.I(IGNORECASE): 忽略大小写(括号内是完整写法,下同)
re.M(MULTILINE): 多行模式,改变'^'和'$'的行为(参见上图)
re.S(DOTALL): 点任意匹配模式,改变'.'的行为
re.L(LOCALE): 使预定字符类 \w \W \b \B \s \S 取决于当前区域设定
re.U(UNICODE): 使预定字符类 \w \W \b \B \s \S \d \D 取决于unicode定义的字符属性
re.X(VERBOSE): 详细模式。这个模式下正则表达式可以是多行,忽略空白字符,并可以加入注释。
请看例子:
import re
text = "JGood is a handsome boy, he is cool, clever, and so on..."
regex = re.compile(r'\w*oo\w*')
print(regex.findall(text)) ['JGood', 'cool']
re 小节
#re.match()
#re.search()
#re.findall()
#re.split()
#re.sub()
re.match()、re.search()可以分为两种情况,第一种不分组第二种分组(方便记忆):
a = 'hello word diao zha tian'
ret = re.match('h\w+',a)
print(ret.group()) #获取匹配到的所有结果
print(ret.groups()) # 获取模型中匹配到的分组情况
print(ret.groupdict())# 获取模型中匹配到的分组结果
############output##############
hello
()
{} ret = re.match('(?P<n>h)(?P<n1>\w+)',a)
print(ret)
print(ret.group()) #获取匹配到的所有结果
print(ret.groups()) # 获取模型中匹配到的分组情况
print(ret.groupdict())# 获取模型中匹配到的分组结果
#?P<n1> = Key
############output############## <_sre.SRE_Match object; span=(0, 5), match='hello'>
hello
('h', 'ello')
{'n': 'h', 'n1': 'ello'}
re.findall()
a = 'hello alex alex adn acd'
n = re.findall('(a)(\w+)',a) #[('a', 'lex'), ('a', 'lex'), ('a', 'dn'), ('a', 'cd')]
print(n) #从左到右,从外到内 ,?P<> 无效
re.split()
在编写计算器的时候可以用re.split() 比如:
def f1(ex):
return eval(ex) #测试用 真实中要自己编写四则运算 a = '1*2+(5/6)+(12*23)/15'
while True:
ret = re.split('\(([^()]+)\)', a, 1)
if len(ret) == 3:
a,b,c = re.split('\(([^()]+)\)', a, 1)
rec = f1(b)
a = a + str(rec) + c
else:
red = f1(a)
print(red)
break
re匹配括号
re.sub() 用于替换匹配的字符串
content = "123abc456"
new_content = re.sub('\d+', 'sb', content)
# new_content = re.sub('\d+', 'sb', content, 1)
print new_content
常用的验证规则:
验证手机号:
(^(13\d|14[57]|15[^4\D]|17[13678]|18\d)\d{8}|170[^346\D]\d{7}) 验证邮箱:
^[a-z0-9]+([._\\-]*[a-z0-9])*@([a-z0-9]+[-a-z0-9]*[a-z0-9]+.){1,63}[a-z0-9]+$ IP:
^(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}$
计算器源码:
import re
def md(date_list,symbol):
''' :param date_list: 匹配到的表达式
:param symbol: 符号
:return: 乘数计算得到的值
'''
a = date_list.index(symbol) #取到符号
if symbol == '*' and date_list[a + 1] != '-': #如果是乘号并且索引的下一个位置不是负号计算
k = float(date_list[a - 1]) * float(date_list[a + 1])
elif symbol == '/' and date_list[a + 1] != '-': #如果是除号并且索引的下一个位置不是负号计算
k = float(date_list[a - 1]) / float(date_list[a + 1])
elif symbol == '*' and date_list[a + 1] == '-': #如果是乘号并且索引的下一个位置是负号计算
k = -(float(date_list[a - 1]) * float(date_list[a + 2]))
elif symbol == '/' and date_list[a + 1] == '-': #如果是除号并且索引的下一个位置是负号计算
k = -(float(date_list[a - 1]) / float(date_list[a + 2]))
del date_list[a - 1], date_list[a - 1], date_list[a - 1] #删除列表里参与计算的索引位置
date_list.insert(a - 1, str(k)) #把新的值插入到列表中
return date_list
#处理混乱的四则,按照先算加减后乘除的原则
def fun(s):
''' :param s: 去除括号后的表达式
:return: 表达式的返回值
'''
list_str = re.findall('([\d\.]+|/|-|\+|\*)',s) #匹配表达式
sum=0
while 1:
if '*' in list_str and '/' not in list_str: #判断乘是否在表达式内
md(list_str, '*')
elif '*' not in list_str and '/' in list_str: #判断乘是否在表达式内
md(list_str, '/') #调用md函数处理除号
elif '*' in list_str and '/' in list_str:
a = list_str.index('*')
b = list_str.index('/')
if a < b:
md(list_str, '*')
else:
md(list_str, '/')
else:
if list_str[0]=='-': #判断是否是负号
list_str[0]=list_str[0]+list_str[1]
del list_str[1]
sum += float(list_str[0])
for i in range(1, len(list_str), 2):
if list_str[i] == '+' and list_str[i + 1] != '-':
sum += float(list_str[i + 1])
elif list_str[i] == '+' and list_str[i + 1] == '-':
sum -= float(list_str[i + 2])
elif list_str[i] == '-' and list_str[i + 1] == '-':
sum += float(list_str[i + 2])
elif list_str[i] == '-' and list_str[i + 1] != '-':
sum -= float(list_str[i + 1])
break
return sum a='1 - 2 * ( (60-30 +(-40.0/5) * (9-2*5/3 + 7 /3*99/4*2998 +10 * 568/14 )) - (-4*3)/ (16-3*2) )'
#循环去除括号
while True:
ret = re.split('\(([^()]+)\)', a, 1)
if len(ret) == 3:
a,b,c = re.split('\(([^()]+)\)', a, 1)
rec = fun(b)
a = a + str(rec) + c else:
red = fun(a)
print(red)
break
Python系列之正则表达式详解的更多相关文章
- Java 正则表达式详解_正则表达式
body{ font-family: "Microsoft YaHei UI","Microsoft YaHei",SimSun,"Segoe UI& ...
- Django url配置 正则表达式详解 分组命名匹配 命名URL 别名 和URL反向解析 命名空间模式
Django基础二之URL路由系统 本节目录 一 URL配置 二 正则表达式详解 三 分组命名匹配 四 命名URL(别名)和URL反向解析 五 命名空间模式 一 URL配置 Django 1.11版本 ...
- Linux文本处理三剑客之grep及正则表达式详解
Linux文本处理三剑客之grep及正则表达式详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.Linux文本处理三剑客概述 grep: 全称:"Global se ...
- 第7.19节 Python中的抽象类详解:abstractmethod、abc与真实子类
第7.19节 Python中的抽象类详解:abstractmethod.abc与真实子类 一. 引言 前面相关的章节已经介绍过,Python中定义某种类型是以实现了该类型对应的协议为标准的,而不 ...
- JavaScript正则表达式详解(一)正则表达式入门
JavaScript正则表达式是很多JavaScript开发人员比较头疼的事情,也很多人不愿意学习,只是必要的时候上网查一下就可以啦~本文中详细的把JavaScript正则表达式的用法进行了列表,希望 ...
- JavaScript正则表达式详解(二)JavaScript中正则表达式函数详解
二.JavaScript中正则表达式函数详解(exec, test, match, replace, search, split) 1.使用正则表达式的方法去匹配查找字符串 1.1. exec方法详解 ...
- python之OS模块详解
python之OS模块详解 ^_^,步入第二个模块世界----->OS 常见函数列表 os.sep:取代操作系统特定的路径分隔符 os.name:指示你正在使用的工作平台.比如对于Windows ...
- python之sys模块详解
python之sys模块详解 sys模块功能多,我们这里介绍一些比较实用的功能,相信你会喜欢的,和我一起走进python的模块吧! sys模块的常见函数列表 sys.argv: 实现从程序外部向程序传 ...
- python中threading模块详解(一)
python中threading模块详解(一) 来源 http://blog.chinaunix.net/uid-27571599-id-3484048.html threading提供了一个比thr ...
随机推荐
- 第2阶段——编写uboot之启动内核和制作Makefile(2)
目标: 1 添加头文件setup.h和serial.h 2 写main函数 2.1 帮内核设置串口0, (内核启动会打印出启动信息) 2.2把内核读入到SDRAM 2.3设置参数(参考u- ...
- 团队作业9——测试与发布(Beta版本)
Deadline: 2017-6-5 22:00PM,以博客发表日期为准 评分基准: 按时交 - 有分,检查的项目包括后文的两个方面 测试报告 发布说明 展示博客(单独一篇博客) 晚交 - 0分 迟交 ...
- 集美大学网络1413第七次作业成绩(团队三) --需求改进&系统设计
题目 团队作业3--需求改进&系统设计 团队作业3成绩 团队/分值 TD BZ GJ CJ SI WBS GS JG DB SS SJ CS DC 总分 1 0.25 0.75 1 0.5 ...
- 【Beta阶段】第一次scrum meeting
Coding/OSChina 地址 1. 会议内容 学号 主要负责的方向 昨日任务 昨日任务完成进度 接下去要做 9 9 PM 博客编写,会议总结,代码整理 100% 准备下一次会议内容,并对已完成的 ...
- 201521123087 《Java程序设计》第1周学习总结
1.学习总结 初步了解面对对象编程思想 学会安装JDK和设置JAVA_HOME,PATH,CLASSPATH环境变量 简单了解java 2.书面作业 1.为什么java程序可以跨平台运行?执行java ...
- Java课程设计—学生成绩管理系统
一. 团队名称.团队成员介绍(需要有照片) 团队名称:进击的712 团队成员 杨雪莹[组长] 201521123005 网络1511 林楚虹 201521123002 网络1511 董美凤 20152 ...
- 纳税服务系统【异常处理、抽取BaseAction】
前言 本博文主要讲解在项目中异常是怎么处理的.一般我们都不会直接把后台异常信息返回给用户,用户是看不懂的.让用户看见一大串的错误代码,这是不合理的.因此我们需要对报错进行处理. 我们在开发的时候是使用 ...
- 工作中对数组的一些处理,整理(结合underscore.js)
1.数组里边相同元素提取成map,并以'',''分隔 例如:var arr = [{a:"xx",b:''xxx''},{a:"xxx",b:''xxxxx'' ...
- 使用Spring的JavaConfig 和 @Autowired注解与自动装配
1 JavaConfig 配置方法 之前我们都是在xml文件中定义bean的,比如: 1 2 3 4 5 6 7 8 <beans xmlns="http://www.springf ...
- 开天辟地-用visualstudio2010编写helloworld
安装好visual之后,创建新项目 向源文件添加helloworld.cpp 编写helloworld代码,编译运行即可 在运行时候出现一个错误,错误和解决方法如下: