- 正则表达式定义
是一个特殊的字符表达式序列,描述了一种字符串的匹配模式,可以用来检查一个串里是否含有某个子串。
将匹配的字符串替换或者取出符合某个条件的子串,或者在指定的文章中抓取特定的字符串等。
Python中处理正则表达式的模块是re,它是python语言中有全部正则表达式功能的模块。
正则表达式由一些普通字符和元字符组成,普通字符包括大小写字母、数字、打印符号,而元字符是具有特殊含义的字符。
匹配过程:
那正则表达式一次和字符串或者文本中的字符串做比较,如果每一个字符都匹配,则匹配成功,只要有一个匹配不成功的字符,则匹配不成功。
- 正则表达式模式
正则表达式是用来匹配字符串的强有力武器,它的设计思想是用一种描述性的语言来给字符串定义一个规则,凡是符合该规则的字符串就认为匹配成功了,否则认为匹配失败。
模式字符串使用一个特殊的语法来表示一个正则表达式:
字母和数字匹配他们本身。
多数字母和数字前加反斜杠时(\)会有特殊的含义。
特殊的标点符号,只有被转义后才能匹配自身。
反斜杠本身需要反斜杠来转义。
只有编译模式才能支持起始位置的设定。
注意:
由于正则表达式通常包含反斜杠等特殊字符,所以我们最好使用原始字符串来表
示他们。如:r’ \d’ ,等价于’ \\d’ ,表示匹配一个数字。
Python正则表达式中,数量词默认都是贪婪的,它们会尽力尽可能多的去匹配
满足的字符,但是如果我们在后面加上问号“ ?” ,就可以屏蔽贪婪模式,表示
匹配尽可能少的字符。如字符串:“ xyyyyzs” ,使用正则“ xy*” ,就会得到
“ xyyyy” ;如果使用正则“ xy*?” ,将只会匹配“ x”
下表列出了正则表达式模式语法中的特殊元素。如果你是使用模式的同时提供了
- 编译正则表达式基础
#coding=utf-8
import re
# 将正则表达式编译成Pattern对象
pattern = re.compile(r'hello')
# 使用Pattern匹配文本,获得匹配结果,无法匹配时将返回None
match = pattern.match('hello world!')
if match:
# 使用Match获得分组信息
print match.group()
- 正则表达式 re.compile
re.compile(pattern, flags=0)
这个方法是pattern类的工厂方法,目的是将正则表达式pattern编译成pattern对象,并返回该对象。
可以把正则表达式编译成一个正则表达式对象。可以把那些经常使用的正则表达式编译成正则表达式对象,
这样可以提高一定的效率。
第二个参数flag是匹配模式,取值可以使用按位或运算符“ |” 表示同时生效,比如re.I | re.M。当然你也可
以在regex字符串中指定模式,比如:
re.compile('pattern', re.I | re.M)
它等价于:
re.compile('(?im)pattern')
flag参数还有一些其他的可选值,之后我们会一一介绍。
re模块提供了很多用于完成正则表达式的功能。那为什么还有使用pattern实例的相应方法替代呢?
使用该pattern模式唯一的好处就是,一处编译,多出复用。
#coding=utf-8
import re
# 将正则表达式编译成Pattern对象
pattern = re.compile(r'hello')
# print pattern
# 使用Pattern匹配文本,获得匹配结果,无法匹配时将返回None
match1 = pattern.match('helloworld!')
if match1:
print u"第一次使用"
# 使用Match获得分组信息
print match1.group()
match2 = pattern.match("hello,everyone, I am coming.")
if match2 :
print u"第二次使用"
print match2.group()
- 正则表达式-- pattern对象属性及方法
Pattern对象是一个编译好的正则表达式,也就是通过re.compile()函数编译后得到结果。
➢通过pattern提供的一系列方法可以对文本进行匹配查找。
➢Pattern不能直接实例化,必须使用re.compile()函数进行构造。
➢pattern提供了几个可读属性及方法用于处理正则表达式。
>>> pattern = re.compile(r'hello')
>>> dir(pattern)
['__class__', '__copy__', '__deepcopy__', '__delattr__', '__doc__', '__format_
, '__getattribute__', '__hash__', '__init__', '__new__', '__reduce__', '__redu
_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__'
'findall', 'finditer', 'flags', 'groupindex', 'groups', 'match', 'pattern', 's
nner', 'search', 'split', 'sub', 'subn']
- 正则表达式--flags属性
#coding=utf-8
import re
# 将正则表达式编译成Pattern对象
p = re.compile(r'(\w+) (\w+)(?P<sign>.*)', re.DOTALL)
#获取编译时用的匹配模式
print "p.flags: ", p.flags
上面的实例中,编译以后返回的对象为p,通过p.flags我们可以查看编译时的选项,不过它显示的不是’ S’ ,而是一个数值16。其实re.S是一个整数,16就是它的值。如果是I,则显示数值为2
- 正则表达式--groups属性
#coding=utf-8
import re
# 将正则表达式编译成Pattern对象
p = re.compile(r'(\w+) (\w+)(?P<sign>.*)', re.DOTALL)
#获取表达式中分组的数量
print "p.groups: ", p.groups
- 正则表达式--groupindex属性
- 正则的用途
- 取数据分析日志
- 做断言
- 正则表达式的全称:regular expression
>>> import re
>>> pattern = re.compile("\d+")
>>> pattern.match("111abc")
<_sre.SRE_Match object at 0x0000000001DBC510>
>>> pattern.match("111abc").group()
'111'
>>> re.match("\d+","123abc")
<_sre.SRE_Match object at 0x0000000001DBC510>
>>> re.match("\d+","123abc").group()
'123'
>>> print re.match("\d+","abc").group()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'NoneType' object has no attribute 'group'
>>> print re.match("ad","100")
None
>>> none.group()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'none' is not defined
>>> print re.match("a","b")
None
None表示没有匹配成功
Compile()进行编译,编译后的pattern对象可以复用
Group()可以显示匹配的结果
>>> re.findall(pattern,"100")
['100']
- 正则表达式由什么组成?字符和元字符
- \d 数字 \s 空白 \w 字母和数字
\D 非数字 \S 非空白 \W 非字母和数字
正则表达式具有贪婪性,加?问号可以抑制它的贪婪性
有时只写一个反斜杠\ 会被当做转义字符,因此要加两个反斜杠或者加r
>>> re.match(r"\d+","100")
<_sre.SRE_Match object at 0x0000000001DBC510>
>>> re.match("\\d+","100")
<_sre.SRE_Match object at 0x00000000025E0510>
- 如何匹配反斜杠?
>>> re.match(r"\\","\\")
<_sre.SRE_Match object at 0x0000000001DBC510>
>>> re.match(r"\\","\")
File "<stdin>", line 1
re.match(r"\\","\")
^
SyntaxError: EOL while scanning string literal
>>> re.match(r"\","\\")
File "<stdin>", line 1
re.match(r"\","\\")
^
SyntaxError: unexpected character after line continuation charac
不加r和\是无法匹配成功的。
6 . . 点匹配:
>>> re.match(r"a.c","axc")
<_sre.SRE_Match object at 0x00000000025E0510>
>>> re.match(r"a.c","a\nc") 除了\n无法匹配,其他都可以
>>> re.match(r"a.c","a\tc")
<_sre.SRE_Match object at 0x0000000001DBC510>
>>> re.match(r"a.c","a\rc")
<_sre.SRE_Match object at 0x00000000025E0510>
- [ ] 匹配
>>> re.match(r"[abc]x","ax")
<_sre.SRE_Match object at 0x0000000001DBC510>
>>> re.match(r"[abc]x","bx")
<_sre.SRE_Match object at 0x00000000025E0510>
>>> re.match(r"[abc]x","cx")
<_sre.SRE_Match object at 0x0000000001DBC510>
[]方括号表示或的关系,只有匹配一个就可以。
>>> re.match(r"[abc]x","xx")
>>> re.match(r"[^abc]x","xx")
<_sre.SRE_Match object at 0x00000000025E0510>
- |是或 {}是或
>>> re.match(r"[abc]{2}x","abx")
<_sre.SRE_Match object at 0x0000000001DBC510>
>>> re.match(r"ab|bcx","abx")
<_sre.SRE_Match object at 0x00000000025E0510>
>>> re.match(r"ab|bcx","abx").group()
'ab'
>>> re.match(r"[ab]|[bc]x","abx").group()
'a'
同学解释过程:
>>> re.match(r"\s+","\n\t\rabc").group()
'\n\t\r'
>>> re.match(r"\s+a","\n\t\rabc").group()
'\n\t\ra'
>>> re.match(r"[ab][bc]x","abx").group()
'abx'
- \d 表示数字
>>> re.match(r"\d+","12").group()
'12'
>>> re.match(r"\d+","122222").group()
'122222'
>>> re.match(r"\d+?","122222").group() 加问号抑制贪婪性
'1'
- \D匹配非数字
>>> re.match(r"\D+","abc122222").group()
'abc'
- \s 匹配空白
>>> re.match(r"\s+","\n\t\rabc").group()
'\n\t\r'
>>> re.match(r"\s+a","\n\t\rabc").group()
'\n\t\ra'
- \S非空白
>>> re.match(r"\S+","abc").group()
'abc'
>>> re.findall(r"[ab]|[bc]bx","abx")
['a', 'b']
- \w 字母和数字
>>> re.match("\w+","abc123").group()
'abc123'
>>> re.match("\w+","123abc123").group()
'123abc123'
>>> re.match("\w+","123_abc123").group()
'123_abc123'
>>> re.match("\w+","123_-abc123").group()
'123_'
>>> re.match("[\w-]+","123_-abc123").group()
'123_-abc123'
- 减号的匹配:
>>> re.match(r"[\w+-]+","hjg+00").group()
'hjg+00'
>>> re.match(r"[\w-+]+","hjg+00").group()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "C:\Python27\lib\re.py", line 141, in match
return _compile(pattern, flags).match(string)
File "C:\Python27\lib\re.py", line 251, in _compile
raise error, v # invalid expression
sre_constants.error: bad character range
直接用- 减号时会报错,因为它是由含义的
所以想要匹配减号必须加反斜杠
>>> re.match(r"[\w\-+]+","hjg+00").group()
'hjg+00'
- *
>>> re.match(r"\d*","123abc").group()
'123' 加星号表示一直向后匹配
>>> re.match(r"\d*?","123abc").group()
'' 加了问号表示匹配0个或多个,所以出现了空
>>> re.match(r"\d*","abc").group()
''
>>> re.match(r"\d*","123abc").group()
'123'
>>> re.match(r"\d*?","123abc").group()
''
>>> re.match(r"\d","123abc").group()
'1'
- >>> re.findall(r"[ab]|[bc]bx","abx")
['a', 'b']
为什么结果没有匹配出abx?为什么结果匹配出的是[‘a’,’b’]?
老师的讲解:
基础知识:1)正则表达式顺序匹配的 2)a|b 这个 模式就是a如果匹配了,b就不会被尝试去匹配了
[ab][bc]x 表示2个条件的或关系,第一个条件是【ab】,第二个条件是[bc]x
第一轮,在匹abx的时候,先用第一个条件去匹配,然后a被匹配到了,这个时候第二个条件就不会被匹配使用了,这个的匹配结果就是a;
第二轮,这次开始从abx的b开始匹配,开始进行第二次匹配:依旧第一个条件去匹配,然后b被匹配到了
>>> re.findall(r"b","abx")
['b']
然后第二个条件被短路了
然后开始第三次匹配,从abx的x开始匹配,啥都匹配不到,然后就悲剧了。。
啥也没有匹配到,最后只有[a,b]被匹配到了
- 加号 +
>>> re.match(r"\d+","123abc").group()
'123'
>>> re.match(r"\d+?","123abc").group()
'1'
加号匹配1次或多次。
- 问号? 匹配0次或1次
>>> re.match(r"\d?","123abc").group()
'1'
两个问号?? 表示最小匹配 匹配0次
>>> re.match(r"\d??","123abc").group()
''
- 点. :点匹配除换行符之外的任意一个字符
- 星*:星匹配前一个字符0次1次或多次
>>> re.match(r"\d.*?","123abc").group()
'1' *星表示0个或多个,加了?问号表示前面的数量取最小,即0个,0个那就是空字符,等价于直接\d
问号用来限制前面的数量,不限制匹配什么值。因此问号前面有存在数量表达的值存在时才起作用。 如:问号,星,加号,{m,n} 贪婪性只会限制这些的数量取最小值。
>>> re.match(r"\d","123abc").group()
'1'
以上两句是等价的。
- {}大括号 控制匹配的长度
>>> re.match("\d{2}","123").group() {2}匹配前一个字符2次
'12'
>>> re.match("\d{3}","123").group()
'123'
>>> re.match("\d{4}","123").group()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'NoneType' object has no attribute 'group'
>>> re.match("\d{4}","12345").group()
'1234'
限制贪婪性:
>>> re.match("\d{1,4}","12345").group() {1,4} 匹配前一个字符1到4次
'1234'
>>> re.match("\d{1,4}?","12345").group()
'1'
>>> re.match("\d{1,4}","12").group()
'12'
>>> re.match("\d{1,4}","12abf").group()
'12'
>>> re.match("\d{1,}","12abf").group() {1,} 匹配前一个字符至少1次
'12'
>>> re.match("\d{,2}","12abf").group() {,2} 匹配前一个字符0到2次,至多2次
'12'
>>> re.match("\d{,2}","1332abf").group()
'13'
- 小练习:匹配年月日时分秒
>>> re.search("\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2}","now is 2017/10/17 18:19:20
,good")
这个不能用match,因为match从第一个开始匹配。
<_sre.SRE_Match object at 0x00000000005EC510>
>>> re.search("\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2}","now is 2017/10/17 18:19:20
,good").group()
'2017/10/17 18:19:20'
老师的方法:
>>> re.search("\d{4}/\d{2}/\d{2}\s+\d+:\d+:\d+","now is 2017/10/17 18:19:20 ,goo
d").group()
'2017/10/17 18:19:20'
- 小练习:"1111 zza1b1c1xx 222" 匹配a1b1c1 一个字母+一个数字的形式,用模糊匹配
>>> re.search(r"\w\d\w\d\w\d","1111 zza1b1c1xx 222").group()
'a1b1c1'
老师的方法: 直接用\w 匹配有可能匹配上两个数字,这样结果就会是错误的
>>> re.search("[a-zA-Z]\d[a-zA-Z]\d[a-zA-z]\d","1111 zza1b1c1xx 222").group
()
'a1b1c1'
>>> re.search("[a-zA-Z]\d+","1111 zza1b1c1xx 222").group()
'a1'
>>> re.search("([a-zA-Z]\d)+","1111 zza1b1c1xx 222").group()
'a1b1c1'
这里使用分组可以简化代码
- ^ 托字符
>>> re.match("^abc","xabc")
>>> re.match("^abc","abc") 必须从字符串的开头才能匹配到
<_sre.SRE_Match object at 0x0000000002724510>
>>> re.match("abc","xabc")
>>> re.search("abc","xabc")
<_sre.SRE_Match object at 0x00000000005EC510>
>>> re.search("^abc","xabc")
>>> re.search("^abc","abc")
<_sre.SRE_Match object at 0x0000000002724510>
- \A 与托字符等价,必须从字符串开头开始匹配
>>> re.search("\Aabc","xabc")
>>> re.search("\Aabc","abc")
<_sre.SRE_Match object at 0x00000000005EC510>
>>>
- $ 必须是结尾匹配,正好匹配上结尾时匹配成功
>>> re.search("abc","akbcabc")
<_sre.SRE_Match object at 0x0000000002724510>
>>> re.search("abc$","abcakbcabc")
<_sre.SRE_Match object at 0x00000000005EC510>
>>> re.search("abc$","abcakbcabc").group() group() 表示匹配了所有内容
'abc'
>>> re.search("abc$","abcakbcabcZ").group()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'NoneType' object has no attribute 'group'
- 小练习 “zzabc11”,”abc”,”abc111”,”111abc”中只匹配出仅有”abc”的
>>> re.search("\Aabc$","abc").group()
'abc'
老师的答案:
>>> re.search("^abc$","abc").group()
'abc'
- 小练习:断言,精确匹配出 {"userid":123} 这里的123是不断变化的
>>> re.search("^userid:\d+$","userid:123").group()
'userid:123'
老师的方法:
>>> re.search(r'^{\"userid\":\d+}$','{"userid":123}').group()
'{"userid":123}'
>>> re.search(r'^{"userid":\d+}$','{"userid":123}').group()
'{"userid":123}'
做自动化断言用处会比较多,精确判定接口返回的结果是很有必要的。
因为里面存在双引号,所以外部使用了单引号。
为什么{\"userid\ 要加反斜杠? 这里其实可以不加的,因为外面用的是单引号,加反斜杠是为了防止被转义。
- \b 表示单词边界,前后没有任何其他东西
>>> re.search(r"\babc"," abc").group()
'abc'
>>> re.search(r"^abc"," abc").group()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'NoneType' object has no attribute 'group'
>>> re.search(r"\babc","=abc").group()
'abc'
>>> re.findall(r"\babc","=abc abc abc")
['abc', 'abc', 'abc']
- \B非边界
>>> re.findall(r"\Babc"," abc abc 1abc").group()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'list' object has no attribute 'group'
>>> re.findall(r"\Babc"," abc abc 1abc")
['abc']
- pattrn
Python通过re模块提供对正则表达式的支持。使用re的一般步骤是先将正则表达式的字符串形式编译为pattern实例,然后使用pattern实例处理文本并获取匹配结果(一个Match实例),最后使用Match实例获取信息,进行其他的操作。
#coding=utf-8
import re
# 将正则表达式编译成Pattern对象
pattern = re.compile(r'hello')
# 使用Pattern匹配文本,获得匹配结果,无法匹配时将返回None
match = pattern.match('hello world!')
if match:
# 使用Match获得分组信息
print match.group()
- 如何匹配 \n ? 点表示匹配任意字符
>>> re.search(r".+","abc\nfgh",re.DOTALL)
<_sre.SRE_Match object at 0x0000000001E2C510>
>>> re.search(r".+","abc\nfgh",re.DOTALL).group()
'abc\nfgh'
re.DOTALL 支持全部
>>> print re.DOTALL
16
>>> re.search(r".+","abc\nfgh",16).group()
'abc\nfgh'
也可以直接用16
>>> re.search(r".+","ABCabc\nfgh",re.DOTALL|re.I).group()
'ABCabc\nfgh'
re.I 不区分大小写
>>> print re.I
2
>>> re.search(r".+","ABCabc\nfgh",re.DOTALL|2).group()
'ABCabc\nfgh'
- flags
>>> pattern = re.compile(r"AB.+",re.DOTALL)
>>> pattern.flags
16
>>> pattern = re.compile(r"AB.+",18)
>>> pattern.match("ab1")
<_sre.SRE_Match object at 0x0000000001E2C510>
>>> pattern.match("ab1").group()
'ab1'
>>> pattern.match("ab1\naa").group()
'ab1\naa'
Compile编译后的pattern可以复用。Flags可以打印出此时的条件
>>> pattern = re.compile(r"AB.+",18)
>>> pattern.flags
18
- 多行匹配模式:re.M
>>> re.search(r"abc$","1\n2\nabc\n").group()
'abc'
>>> re.search(r"abc$","1abc\n2\n\n").group()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'NoneType' object has no attribute 'group'
>>> re.search(r"abc$","1abc\n2\n\n",re.M).group()
'abc'
>>> re.search(r"abc$","1abc\n2abc\n\n",re.M).group()
'abc'
>>> re.search(r"abc$","1\n2abc\n\n",re.M).group()
'abc'
>>> re.findall(r"abc$","1\n2abc\nabc\n",re.M)
['abc', 'abc']
Re.DOTALL 可以把点变成匹配全部,包括\n
Findall 可以找出全部匹配的内容
- groups 查看有几个分组
#coding=utf-8
import re
# 将正则表达式编译成Pattern对象
p = re.compile(r'(\w+) (\w+)(?P<sign>.*)', re.DOTALL)
#获取表达式中分组的数量
print "p.groups: ", p.groups
- groupindex属性 查出是第几个分组及名字
#coding=utf-8
import re
# 将正则表达式编译成Pattern对象
p = re.compile(r'(\w+) (\w+)(?P<sign>.*)', re.DOTALL)
#获取表达式中所有分组的别名和分组序号组成的字典
print "p.groupindex: ", p.groupindex
- match在使用pattern模式时,可以加开始位置和结束位置
>>> pattern = re.compile(r"\d+")
>>> pattern.match("abc123").group()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'NoneType' object has no attribute 'group'
>>> pattern.match("abc123",3).group()
'123'
>>> pattern.match("abc123",3,4).group()
'1'
直接用re去写它是不支持起始和结束位置设定的。
>>> re.match(r"\d+","abc123",3).group()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "C:\Python27\lib\re.py", line 141, in match
return _compile(pattern, flags).match(string)
File "C:\Python27\lib\re.py", line 251, in _compile
raise error, v # invalid expression
sre_constants.error: internal: unsupported template operator
- pattern.search 方法
#coding=utf-8
import re
#匹配多个数字,至少一个空格,0个或多个单词字符(字母和数字)
pattern = re.compile('\d+\s?\w*')
matchResult = pattern.search("12bcr123Abc123", 0, 10)
#从0到9之间的字符进行匹配
if matchResult:
print u'匹配的内容是:', matchResult.group()
else:
print u"正则表达式没有匹配到内容"
- re. search方法
扫描整个字符串并返回第一次成功的匹配对象,如果匹配失败,则返回None。
该方法与pattern.search()方法区别在于,它不能指定匹配的区间pos和endpos两个参数。
- findall它的作用是查找字符串中所有能匹配的字符串,并把结果存于列表中,然后返回该列表
特殊之处:
- 有圆括号时只取出括号内的内容: 括号与括号之间是与的关系
>>> re.findall(r"(a)b(c)","abc abc")
[('a', 'c'), ('a', 'c')]
>>> re.findall(r"(a)(b)(c)","abc abc")
[('a', 'b', 'c'), ('a', 'b', 'c')]
- 有一个圆括号时只取出一个里面的东西
>>> re.findall(r"(a)bc","abc abc")
['a', 'a']
- 没有圆括号时取出全部
>>> re.findall(r"abc","abc abc")
['abc', 'abc']
分组小练习:
>>> re.findall(r"(\d+) (\d+)","123 456 789 1011")
[('123', '456'), ('789', '1011')] 这里匹配了两次 ,分成了两个元组
>>> re.findall(r"(\d+)(\s+)(\d+)","123 456 789 1011")
[('123', ' ', '456'), ('789', ' ', '1011')]
>>> re.findall(r"\d+","1123 456 789 1011")
['1123', '456', '789', '1011']
- Finditer 匹配所有满足的字符串,存成一个迭代器,这样可以节省内存空间。
>>> for i in re.finditer(r'[A-Za-z]+','one12two34three56four'):
... print i.group()
...
one
two
three
four
>>>
- re.split 切割
>>> re.split(r"\d+","abc122errr333sfj")
['abc', 'errr', 'sfj']
>>> re.split(r"\d+","abc122errr333sfj",2)
['abc', 'errr', 'sfj']
>>> re.split(r"\d+","abc122errr333sfj",1)
['abc', 'errr333sfj'] 可以设置切割次数
- Sub 替换
>>> re.sub(r"\d","digit","1c2d3e")
'digitcdigitddigite'
>>> re.sub(r"\d","*","1c2d3e")
'*c*d*e'
>>> re.sub(r"\d","*","1c2d3e",2)
'*c*d3e'
>>> re.sub(r"\d","*","1c2d3e",1)
'*c2d3e' 可以设置替换次数
也可以使用pattern模式
>>> pattern = re.compile(r"\d+")
>>> pattern.sub("*","1w2e3r")
'*w*e*r'
- 小练习:统计一句话有几个单词 I am a boy,She is a girl. We are friend.
思路:什么是单词?多个字母组成
>>> re.findall(r"\w+","I am a boy,She is a girl. We are friend.")
['I', 'am', 'a', 'boy', 'She', 'is', 'a', 'girl', 'We', 'are', 'friend']
- Subn 可以看出被替换的对象有几个
>>> pattern = re.compile(r"\d+")
>>> pattern.subn("","1w2e3r")
('wer', 3)
- 例题讲解:
#coding=utf-8
import re
p = re.compile(r'(\w+) (\w+)')
s = 'i say, hello world!'
#\2, \1表示分组引用,分别代表第二个分组,第一个分组
print p.sub(r'\2 \1', s)
#当repl为方法时,将匹配的结果m传入方法
def func(m):
return m.group(1).title() + ' ' + m.group(2).title()
print p.sub(func, s) 把想要替换成的内容存在了函数结果里面,然后去替换
解释:
>>> re.sub(r"(\w+) (\w+)","*","i say,hello world!")
'*,*!'
>>> re.sub(r"(\w+) (\w+)","*$","i say,hello world!")
'*$,*$!'
Group(1) 和group(2)是什么?
第一个分组和第二个分组
>>> re.search(r"(\d+) (\d+)","12 23").group()
'12 23'
>>> re.search(r"(\d+) (\d+)","12 23").group(1)
'12'
>>> re.search(r"(\d+) (\d+)","12 23").group(2)
'23'
>>> "abc".title()
'Abc'
- 回溯一下原始要匹配的字符串是什么 .string
>>> pattern = re.compile("\d+")
>>> pattern.search("1a2b").group()
'1'
>>> pattern.search("1a2b").string
'1a2b'
- 例题讲解:高级正则替换方法
import re
def multiply(m):
# 将分组0的值转成整型
v = int(m.group(0))
# 将分组0的整型值乘以2,然后返回
return str(v * 2)
# 使用multiply方法作为第二个参数,将匹配到的每个数字作为参数传入multiply#
函数,处理后将返回结果替换为相应字符串
result = re.sub("\d+", multiply, "10 20 30 40 50")
print result
- findall,serach,sub的工作原理
findall:"\d" "1a2b3c4d" [1,2,3,4]
search: "\d+" "a12345b3c4d" 12345
sub : "\d+" "a123b345c" a*b*c
- re属性 匹配时使用的pattern对象,也就是匹配到内容的正则表达式对象。
#coding=utf-8
import re
m = re.match(r'(\w+)! (\w+)(?P<sign>.*)','Hi! gloryroad!')
print m.re
print m.group("sign") 通过分组名打印出匹配到的内容
- pos属性 该属性表示文本中正则表达式开始搜索的索引。值与Pattern.match()和Pattern.seach()方法中的同名参数相同。
#coding=utf-8
import re
m = re.match(r'(\w+)! (\w+)(?P<sign>.*)', 'Hi! gloryroad!')
print m.pos
- 分组嵌套 没啥大用
#coding=utf-8
import re
matchResult=re.search(r'(a(b)c)d','abcdefg')
print matchResult.group(1)
print matchResult.group(2)
- group()函数传多个参数 没啥大用
#coding=utf-8
import re
p = re.compile('(a(b)c)d')
m = p.match('abcd')
resTup = m.group(1,2,1)
print resTup
- groups() 把所有匹配分组的内容做打印;以元组形式返回全部分组截获的字符串。相当于调用group(1,2,…last)。没有截获字符串的组以默认值None代替。
#coding=utf-8
import re
p = re.compile('[a-z]+\s(\d)(\w)')
matchResult = p.match("aa 1w31")
if matchResult:
print matchResult.groups()
- start([group=0])返回指定的组截获的子串在string中的起始索引(子串第一个字符的索引)。默认为第0组。
#coding=utf-8
import re
m = re.search(r'(\w+)! (\w+) (\w+)','HMan! gloryroad train')
print m.start(1)
#表示第一个分组被匹配的字符串位置索引
print m.start(2)
#表示第二个分组被匹配的字符串位置索引
print m.start(3)
#表示第三个分组被匹配的字符串位置索引
- end([group=0])返回指定的组截获的子串在string中的结束索引(子串最后一个字符的索引)。 group默认值为0。
#coding=utf-8
import re
m = re.search(r'(\w+)! (\w+) (\w+)','HMan! gloryroad train')
#获取第一个分组被匹配内容的最后一个字母在被匹配字符串的索引位置
print m.end(1)
#获取第二个分组被匹配内容的最后一个字母在被匹配字符串的索引位置
print m.end(2)
#print m.end(3)
- span([group])该方法表示以元组的形式返回 (start(group), end(group)),即某个分组的匹配文字内容在被匹配字符串的开始索引位置和结束索引位置。
#coding=utf-8
import re
m = re.search(r'(\w+)! (\w+) (\w+)','HMan! gloryroad train')
#获取第一个分组匹配文字内容在被匹配字符串的开始索引位置和结束索引位置
print m.span(1)
print m.span(2)
print m.span(3)
- expand(template)将匹配到的分组代入template中然后返回。 template中可以使用\id或\g<id>、 \g<name>引用分组,但不能使用编号0。 \id与\g<id>是等价的;但\10将被认为是第10个分组,如果你想表达\1之后是字符'0',只能使用\g<1>0。
#coding=utf-8
import re
m = re.search(r'(\w+)! (\w+) (\w+)','HMan! gloryroad train')
#将匹配的结果带入
print m.expand(r'resut:\3 \2 \1')
print m.expand(r'resut:\3 \2 \2')
- groupdict([default=None])该函数的作用是,将所有匹配到并且指定了别名的分组,以别名为key,匹配到的字串为value,存于字典中,然后返回这个字典。如果表达式中未设置别名分组,就会返回一个空字典。
#coding=utf-8
import re
line = "This is the last one"
res = re.match( r'(?P<group1>.*) is (?P<group2>.*?) .*', line, re.M|re.I)
groupDict = res.groupdict()
if groupDict:
print groupDict
else :
print "无别名分组"
- 无名分组
分组就是用一对圆括号“ ()” 括起来的正则表达式,匹配出的内容就表示一个分组。
取代码中的超链接中的文本
#coding=utf-8
import re
s = u'<div><a href="https://support.google.com/chrome/?
p=ui_hotword_search"target="_blank">更多</a><p>dfsl</p></div>'
matchResult = re.search(r'<a.*>(.*)</a>', s).group(1)
print matchResult
# 上面的实例等价于下面的实例
print re.match(r'.*<a.*>(.*)</a>', s).group(1)
- 命名分组
命名分组就是给具体有默认分组编号的组另外再起一个别名,方便以后的引用。
命令分组的语法格式如下: (?P<name>正则表达式)
语法格式中的字符P必须是大写的“ P” ,name是一个合法的标识符,表示分组的别名。
提取字符串中的ip地址
#coding=utf-8
import re
s = "ip='230.192.168.78',version='1.0.0'"
res = re.search(r"ip='(?P<ip>\d+\.\d+\.\d+\.\d+).*", s)
print res.group('ip')#通过命名分组引用分组
- 多个命名分组
#coding=utf-8
import re
matchResult=re.search(r'(?P<last>\w+),(?P<first>\w+),(?P<phone>\S
+)',"phone,number,15817934235")
#使用命名分组获取第一个分组的内容
print matchResult.group('last')
#使用命名分组获取第二个分组的内容
print matchResult.group('first')
#使用命名分组获取第三个分组的内容
print matchResult.group('phone')
- 正则表达式—后向引用
正则表示式中,放在圆括号“()”中的表示是一个分组。然后我们就可以对整个组使用一些正则
操作,例如重复操作符。
要注意的是,只有圆括号“()”才能用于形成分组, “ ”用于定义字符串,而“{}”用于定义重复操作。
当用“()”定义了一个正则表达式分组后,正则引擎就会把匹配的组按照顺序进行编号,然后存
入缓存中。这样我们就可以在后面对已经匹配过的内容进行引用,这就叫后向引用。
后向引用的语法:
1、通过索引引用
\数字
\1表示引用第一个分组, \2引用第二个分组,以此类推, \n引用第n个组,而\0则表示引用整个
被匹配的正则表达式本身。
2、通过命名分组名进行引用(如果有的话)
(?P=name)
字符P必须是大写的P, name表示命名分组的分组名。
通过默认分组编号进行后向引用:
import re
s = 'aaa111aaatestaaa'
print re.findall(r'([a-z]+)\d+(\1).*(\1)', s)
被匹配到的a:
aaa111aaatestaaa
import re
s = 'aaa111abaatestaaa'
print re.findall(r'([a-z]+)\d+(\1).*(\1)', s)
老师的分析过程如下:
通过命名分组进行后向引用:
#coding=utf-8
import re
#后向引用,匹配两个一样的单词
res = re.search(r'(?P<name>go)\s+(?P=name)\s+(?P=name)', 'go go go')
print res.group()
print res.group('name')
变形:
#coding=utf-8
import re
#后向引用,匹配两个一样的单词
res = re.search(r'(?P<name>go)\s+(?P=name)\s+(?P=name)', '11 11 13') #有一个不同时会匹配失败
print res.group()
print res.group('name')
交换字符串的位置:
#coding=utf-8
import re
s = 'abc.xyz'
# 交换.号两边的字符串
res = re.sub(r'(.*)\.(.*)', r'\2.\1', s)
print res
(.*)\.(.*)'匹配要替换的内容
r'\2.\1'被替换后的内容
s 被替换的字符串
小练习:abcdef 把ab和ef换个位置
自己的方法:
#coding=utf-8
import re
s = 'abcdef'
# 交换.号两边的字符串
res = re.sub(r'(ab)(\w+)(ef)', r'\3\2\1', s)
print res
- 前向肯定断言的语法:
(?<=pattern)
前向肯定断言表示你希望匹配的字符串前面是pattern匹配的内容时,才匹配。
>>> result = re.search(r"(?<=\d{3})[a-z]+","123abc")
>>> print result.group()
Abc
(?<=\d{3}) 这里明确前面有3位数字才能匹配成功
必须知道确定的位数才可以,否则无法使用。
- 后向肯定断言的语法:
(?=pattern)
后向肯定断言表示你希望匹配的字符串的后面是pattern匹配的内容时,才匹配。
>>> result = re.search(r"[a-z]+(?=\d+)","123abc456")
>>> print result.group()
Abc
[a-z]+(?=\d+) 后向匹配可以模糊,不知道具体位数也能用。
- 前向否定断言的语法:
(?<!pattern)
前向否定断言表示你希望匹配的字符串的前面不是pattern匹配的内容时,才匹配。
>>> result = re.search(r"(?<!=\d{3})[a-z]+","123abc")
>>> print result.group()
abc
这样的也匹配上了是什么情况?
多写了一个“=”
>>> result = re.search(r"(?<!\d{3})[a-z]+","123abc")
>>> print result.group()
bc
- 后向否定断言的语法:
(?!pattern)
后向否定断言表示你希望匹配的字符串后面不是pattern匹配的内容时,才匹配。
>>> result = re.search(r"[a-z]+(?!\d+)","123abc456")
>>> print result.group()
ab