定义
正则表达式regular expression: 描述了一种字符串匹配的模式(pattern),可以用来检查一个串是否含有某种子串、将匹配的子串替换或者从某个串中取出符合某个条件的子串等。
使用正则表达式有2个原因:
- 数据挖掘
从一大堆文本中找出一小堆文本时(与给定模式匹配)。例如email、url、phone - 验证合法性
确认获得的数据是你期望的,尤其是来自用户的。例如:电话号码格式
原始字符串和正常字符串的区别- 原始字符串不会将\字符解释成一个转义字符。即:无法转义引号避免字符串结束
- 原始字符串对于正则表达式尤其有用
基本正则表达式
匹配纯文本是基本应用,可以使用in操作符或者str.index代替。re强大之处在于能够指定用于匹配的文本模式
- 字符组
区间:[0-9] [A-Za-z]
取反:[^a-z]
快捷方式: \d匹配数字字符,\s匹配空白字符,\b匹配长度为0的字串 \w匹配除空格以外的所有字符
字符串的开始和结束: ^开始 $结束
任意字符: .字符
可选字符:honou?r 匹配:honour和honor
重复:{N}匹配重复次数,例如:[\d]{3}-[\d]{4} 匹配 867-5309
重复区间: '[\d]{3,4}'匹配3个数字或4个数字 ‘[\d]{3,4}?‘尽可能少的匹配
开闭区间:’[\d]{1,}’ 匹配至少1个数字
速写:+字符(一个或多个) *字符(0个或多个); 例如:[\d]+ 等价于[\d]{1,}
- 可选字符:honou?r 匹配:honour和honor
- 重复{N}
匹配重复次数,例如:[\d]{3}-[\d]{4} 匹配 867-5309
重复区间: '[\d]{3,4}'匹配3个数字或4个数字 ‘[\d]{3,4}?‘尽可能少的匹配
开闭区间:’[\d]{1,}’ 匹配至少1个数字
速写:+字符(一个或多个) *字符(0个或多个); 例如:[\d]+ 等价于[\d]{1,}
import re
match = re.search(r'[Pp]ython', 'Python 3')
match = re.search(r'[a-z]', '3')
match = re.search(r'\bcorn\b', 'corn')
match = re.search(r'\w', 'Python 3')
match = re.findall(r'\w', 'Python 3') #\w无法与空字符匹配
match = re.search(r'corn\B', 'corner') #corn
match = re.search(r'^python', 'this is python')
print match
#print match.group()
- 分组
分组方法 | 描述 |
---|---|
| | 左右表达式任意匹配一个 |
(…) | 分组匹配,从左到右,每遇到一个编号加1 |
(?P…) | 命名分组:除了分组序号外,指定一个 name的别名 |
<number> | 引用编号为的分组匹配到的字符串 |
(?P=name) | 引用别名为的分组匹配到的串 |
- 零分组:获得完整匹配(group(0))
- 命名分组:
- 引用已经存在的分组:回溯引用:\1匹配第一个分组 \2匹配第二个分组
>>> pat = re.compile(r'(a)\w(c)')
>>> pat.match('abcefg').group()
'abc'
>>> pat.match('abcefg').group(0)
'abc'
>>> pat.match('abcefg').group(1)
'a'
>>> pat.match('abcefg').group(2)
'c'
>>> pat = re.compile(r'www\.(.*)\..{3}')
>>> pat.match('www.baidu.com').group(0)
'www.baidu.com'
>>> pat.match('www.baidu.com').group(1)
'baidu'
>>> pat = re.compile(r'(?P<K>a)\w(c)') #分2组:命名分组+匿名分组
>>> pat.search('abcdefg').groups() #取所有分组,元组形式返回
('a', 'c')
>>> pat.search('abcdefg').group(0) #默认返回匹配的字符串
'abc'
>>> pat.search('abcdefg').group(1) #取分组1,适用于match
'a'
>>> pat.search('abcdefg').group(2) #取分组2,适用于match
'c'
>>> pat.search('abcdefg').groupdict() #命名分组可以返回一个字典【专有】,匿名分组也没有
{'K': 'a'}
>>> pat = re.compile(r'(?P<M>[\d]{3})-(?P<N>[\d]{4})')
>>> pat.search('123-4567').groupdict()
{'M': '123', 'N': '4567'}
>>> pat.match('123-4567').groupdict()
{'M': '123', 'N': '4567'}
>>> pat = re.compile(r'<([\w*]+)>stuff</\1>') # 回溯引用\1即([\w*]+)
>>> pat.search('<foo>stuff</foo>').groups()
('foo',)
Python中的正则表达式
re模块
- search函数:接受一个正则表达式和一个字符串,并返回发现的第一个匹配。如果没匹配则返回None
- 缺点:它仅仅返回最近的一个以match对象形式的匹配。如果在一个字符串内存在多个匹配,re.search只会返回第一个匹配。
- 如果想返回多个匹配,需要用到findall与finditer函数
- match对象:用于获取关于匹配信息的方法。最重要的是group方法。
match类似于search,区别:仅仅搜索从字符串开始的第一个匹配- group:返回一个包含匹配文本的字符串
- groups:调出正则表达式的一部分
- groupdict
- findall与finditer函数:返回所有非重叠匹配(列表与生成器),包括空匹配。
>>> import re
>>> re.search(r'fox', 'The quick brown fox jumped...')
<_sre.SRE_Match object at 0x073F77C8>
>>> match = re.search(r'fox', 'The quick brown fox jumped...')
>>> match.group()
'fox'
>>> re.findall(r'o', 'The quick brown fox jumped...')
['o', 'o']
>>> print re.match('super', 'superstition').span()
(0, 5)
>>> print re.match('super', 'superstition').group()
super
>>> print re.search('super', 'superstition').span()
(0, 5)
>>> print re.search('super', 'superstition').group()
super
>>> print re.search('super', 'insuperstition').group()
super
先行断言
标记
- 不区分大小写
- ASCII与Unicode
- UNICODE:标记正则表达式引擎遵循python3的行为
- ASCII:标记在python2中不可以
- 点匹配换行符
- re.DOTALL .字符除了匹配其他字符外,还匹配换行符
- re.MULTILINE: 仅能够匹配字符串开始与结束的^与$字符可以匹配字符串内任意行的开始与结束
- 详细模式: VERBOSE: 允许复杂的正则表达式以更容易阅读的方式表示
- 调试模式:DEBUG: 在编译正则表达式时将一些调试信息输出到sys.stderr
- 使用多个标记:re.DOTALL | re.MULTILINE
- 内联标记: 在正则表达式开始部分加上一个特殊语法
例如:>>> re.search(’(?i)FOO’, ‘foo’).group()
‘foo’ - 替换:re.sub(正则表达式,替换的字符串,被搜索的原始字符串)
- ASCII与Unicode
已编译的正则表达式
- python正则表达式实现的一个最终功能是:已编译的正则表达式
- re.compile函数:返回一个已编译的正则表达式对象,可以被复用
>>> regex = re.compile('[\d]+')
>>> regex.search('1 mile is equal to 5280 feet.')
RE使用的步骤:
- 1.使用compile将表示正则的字符串编译为一个pattern对象
- 2.使用patern对象提供一系列方法对文本进行查找匹配,获得匹配结果:一个Match对象
- 3.最后使用Match对象提供的属性和方法获得信息,根据需要进行操作
RE常用函数
- group() 获得一个或者多个分组匹配的字符串,当获得整个匹配的字符串时,之间使用group或者group(0)
- start:获取分组匹配的字串在整个字符串中的起始位置,参数默认为0
- end:获取分组匹配的字串在整个字符串中的结束位置,默认为0
- span:返回的区间(start(group), end(group))
>>> import re
>>> p = re.compile(r'\d+')
>>> m = p.match("ane12two3456three789four", 3, 26)
>>> print (m)
<re.Match object; span=(3, 5), match='12'>
>>> print (m[0])
12
>>> print (m.start(0))
3
总结:
(1) match可以输入参数表示起始位置
(2) 查找到的结果只包含一个,表示第一次进行匹配成功的内容
示例2
# re.I表示忽略大小写
>>> p = re.compile(r'([a-z]+) ([a-z]+)', re.I)
>>> m = p.match("I am realy love wanglujing ")
>>> print (m)
<re.Match object; span=(0, 4), match='I am'>
>>> print (m.group(0))
I am
>>> print (m.group(1), m.start(1), m.end(1)) #第一组信息
I 0 1
>>> print (m.groups())
('I', 'am')
查找
- search(str, [, pos[, endpos]]): 在字符串中查找匹配,pos和 endpos表示起始位置
- findall:查找所有
- finditer:查找,返回一个iter结果
>>> p = re.compile(r'\d+')
>>> m = p.search('one123twothree345435four')
>>> print (m.group())
123
>>> p = re.compile(r'\d+')
>>> m = p.search('one123twothree345435four')
>>> print m.group()
SyntaxError: invalid syntax
>>> print (m.group())
123
>>> import re
>>> rst = p.findall("one123twothree345435four")
>>> print (type(rst))
<class 'list'>
>>> print (type(rst), rst)
<class 'list'> ['123', '345435']
sub替换
sub(rep1, str[,count])
>>> p = re.compile(r'(\w+) (\w+)')
>>> s = "hello 123 wang 456 lujing, I love you"
>>> rst = p.sub(r'hello world', s)
>>> print (rst)
hello world hello world lujing, hello world you
匹配中文
- 大部分中文内容表示的范围是[u4e00-u9fa5], 不包含全角标点
>>> import re
>>> title = u'世界 你好, hello world'
>>> p = re.compile(r'[\u4c00-\u9fa5]+')
>>> rst = p.findall(title)
>>> print (rst)
['世界', '你好']
贪婪和非贪婪
- 贪婪:尽可能多的匹配,(*)表示贪婪匹配
- 非贪婪:找到符合条件的最小内容即可,(?)表示非贪婪
- 正则默认使用贪婪匹配
>>> import re
>>> title = u'<div>name</div><div>age</div>'
>>> p1 = re.compile(r"<div>.*</div>")
>>> p2 = re.compile(r"<div>.*?</div>")
>>> m1 = p1.search(title)
>>> print (m1.group()) #贪婪
<div>name</div><div>age</div>
>>> m2 = p2.search(title)
>>> print (m2.group()) #非贪婪
<div>name</div>