正则表达式之match()
正则表达式是处理字符串的强大工具,有自己特定的语法结构,可以实现字符串的检索、替换、匹配验证。
开源中国提供的正则表达式测试工具,输入待匹配的文本,然后选择常用的正则表达式就可以得出相应的匹配结果了。
对于URL来说,可以用下面的正则表达式匹配:[a-zS-z]+://[^\s]*。
用这个正则表达式去匹配一个字符串,如果中国字符串包含类似URL的文本,就会被提取出来。
这个正则表达式看上去是乱糟糟的一团,其实不然。如a-z代表匹配任意小写字母,\s表示匹配任意的空白字符,*就代表匹配前面的字符可以任意多个。
python的re库提供了整个正则表达式的实现。
1.match()
match()方法会尝试从字符串的起始位置匹配正则表达式,如果匹配,就返回匹配成功的结构;如果不匹配,就返回None。示例如下:
import re
content='Hello 1234567 World_This is a Regex Demo'
result=re.match('^Hello\s(\d+)\sWorld',content)
print(result)
print(result.group())
print(result.group(1))
print(result.span())
运行结果如下:
<re.Match object; span=(0, 19), match='Hello 1234567 World'>
Hello 1234567 World
1234567
(0, 19)
group()会输出完整的匹配结果,而group1()会输出第一个被()包围的匹配结果。
1.通用匹配
.*(点星)是一个万能匹配。其中.(点)可以匹配任意字符(除换行符),*代表匹配前面的字符无限次。
import re
content='Hello 1234567 World_This is a Regex Demo'
result=re.match('^Hello.*Demo$',content)
print(result)
print(result.group())
print(result.span())
这里我们将中间部分直接省略,全用.*来代替,最后加一个结尾字符串。运行结果如下:
<re.Match object; span=(0, 40), match='Hello 1234567 World_This is a Regex Demo'>
Hello 1234567 World_This is a Regex Demo
(0, 40)
2.贪婪与非贪婪
import re
content='Hello 1234567 World_This is a Regex Demo'
result=re.match('^He.*(\d+).*Demo$',content)
print(result)
print(result.group(1))
这里我们依然想获取中间的数字,所以中间依然写的是(\d+)。而数字两侧由于内容比较杂乱,所以想省略来写。运行结果如下:
<re.Match object; span=(0, 40), match='Hello 1234567 World_This is a Regex Demo'>
7
可以发现我们只得到了7这个数字。这里涉及一个贪婪匹配与非贪婪匹配的问题。在贪婪匹配下, .*会匹配尽可能多的字符。正则表达式中.*后面是\d+,也就是至少一个数字,并没有指定具体多少给数字,因此,.*就尽可能匹配多的字符,这里就把123456匹配了,给\d+留下一个可满足条件的数字7。
这时,我们可以使用非贪婪匹配来解决这个问题。它的写法是.*?。
非贪婪匹配就是尽可能匹配少的字符。当.*?匹配到Hello后面的空白字符时,再往后的字符就是数字了,而\d+恰好可以匹配,.*?就不再进行匹配,交给\d+去匹配后面的数字。
但需要注意,如果匹配的结果在字符串尾,.*?就可能匹配不到任何内容了。
import re
content='http://weibo.com/comment/kEraCN'
result1=re.match('http.*?comment/(,*?)',content)
result2=re.match('http.*?comment/(.*)',content)
print('result1',result1.group(1))
print('result2',result2.group(1))
运行结果如下:
result1
result2 kEraCN
可以观察到,.*?没有匹配到任何结果,而.*则尽量匹配多的内容,成功得到了匹配结果。
3.修饰符
正则表达式可以包含一些可选标志修饰符来控制匹配的模式。修饰符被指定为一个可选的标志。
import re
content='''Hello 1234567 World_This
is a Regex Demo
'''
result=re.match('^He.*?(\d+).*?Demo$',content)
print(result.group(1))
与上例相仿,我们在字符串中加了换行符,但运行直接报错,我们又调用了group()方法导致AttributeError。
.匹配的是除换行符之外的任意字符每当遇到换行符,.*?就不能匹配了,所以导致匹配失败,这里只需加一个修饰符re.S,即可修正这个错误:result=re.match('^He.*?(\d+).*?Demo$',content,re.S)
4.转义匹配
如果目标字符串里就包含,,就需要用到转义匹配:
import re
content='(百度)www.baidu.com'
result=re.match('\(百度\)www\.baidu\.com',content)
print(result)
当遇到用于正则匹配模式的特殊字符时,在前面加反斜线转义一下即可。例如.就可以用\.来匹配,运行结果如下:
已连接到 pydev 调试器(内部版本号 231.9011.38)<re.Match object; span=(0, 17), match='(百度)www.baidu.com'>
可以看到,这里成功匹配到了原字符串。