《Python高级编程》(九)正则表达式和RE模块

定义

正则表达式regular expression: 描述了一种字符串匹配的模式(pattern),可以用来检查一个串是否含有某种子串、将匹配的子串替换或者从某个串中取出符合某个条件的子串等。

使用正则表达式有2个原因:

  • 数据挖掘
    从一大堆文本中找出一小堆文本时(与给定模式匹配)。例如email、url、phone
  • 验证合法性
    确认获得的数据是你期望的,尤其是来自用户的。例如:电话号码格式
    原始字符串和正常字符串的区别
    • 原始字符串不会将\字符解释成一个转义字符。即:无法转义引号避免字符串结束
    • 原始字符串对于正则表达式尤其有用

基本正则表达式

匹配纯文本是基本应用,可以使用in操作符或者str.index代替。re强大之处在于能够指定用于匹配的文本模式

  1. 字符组

区间:[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,}

  1. 可选字符:honou?r 匹配:honour和honor
  2. 重复{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. 分组
分组方法描述
|左右表达式任意匹配一个
(…)分组匹配,从左到右,每遇到一个编号加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(正则表达式,替换的字符串,被搜索的原始字符串)

已编译的正则表达式

  • 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>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值