python中正则表达式的使⽤详解
从学习Python⾄今,发现很多时候是将Python作为⼀种⼯具。特别在⽂本处理⽅⾯,使⽤起来更是游刃有余。
说到⽂本处理,那么正则表达式必然是⼀个绝好的⼯具,它能将⼀些繁杂的字符搜索或者替换以⾮常简洁的⽅式完成。
我们在处理⽂本的时候,或是查询抓取,或是替换.
⼀.查
如果你想⾃⼰实现这样的功能模块,输⼊某⼀个ip地址,得到这个ip地址所在地区的详细信息.
但是⼈家没有提供api供外部调⽤,但是我们可以通过代码模拟查询然后对结果进⾏抓取.
通过查看这个相应页⾯的源码,我们可以发现,结果是放在三个<li></li>中的
复制代码代码如下:
<table width="80%" border="0" align="center" cellpadding="0" cellspacing="0">
<tr>
<td align="center"><h3>ip138 IP查询(搜索IP地址的地理位置)</h3></td>
</tr>
<tr>
<td align="center"><h1>您查询的IP:121.0.29.231</h1></td>
</tr>
<tr>
<td align="center"><ul class="ul1"><li>本站主数据:浙江省杭州市阿⾥巴巴</li><li>参考数据⼀:浙江省杭州市阿⾥巴巴</li><li>参考数据⼆:浙江省杭州市阿⾥巴巴</li></ul></td>
</tr>
<tr>
<td align="center">如果您发现查询结果不详细或不正确,请使⽤<a href="ip_add.asp?ip=121.0.29.231"><font
color="#006600"><b>IP数据库⾃助添加</b></font></a>功能进⾏修正<br/><br/>
<iframe src="/jss/bd_460x60.htm" frameborder="no" width="460" height="60" border="0" marginwidth="0" marginheight="0" scrolling="no"></iframe><br/><br/></td>
</tr>
<form method="get" action="ips8.asp" name="ipform" onsubmit="return checkIP();">
<tr>
<td align="center">IP地址或者域名:<input type="text" name="ip" size="16"> <input type="submit" value="查询"><input type="hidden" name="action" value="2"></td>
</tr><br>
<br>
</form>
</table>
如果你了解正则表达式你可能会写出
正则表达式
复制代码代码如下:
(?<=<li>).*?(?=</li>)
这⾥使⽤了前瞻:lookahead 后顾: lookbehind,这样的好处就是匹配的结果中就不会包含html的li标签了.
如果你对⾃⼰写的正则表达式不是很⾃信的话,可以在⼀些在线或者本地的正则测试⼯具进⾏⼀些测试,以确保正确.
接下来的⼯作就是如果⽤Python实现这样的功能,⾸先我们得将正则表达式表⽰出来:
复制代码代码如下:
r"(?<=<li>).*?(?=</li>)"
Python中字符串前⾯加上前导r这个字符,代表这个字符串是R aw String(原始字符串),也就是说Python字符串本⾝不会对字符
串中的字符进⾏转义.这是因为正则表达式也有转义字符之说,如果双重转义的话,易读性很差.
这样的串在Python中我们把它叫做"regular expression pattern"
如果我们对pattern进⾏编译的话
复制代码代码如下:
prog = repile(r"(?<=<li>).*?(?=</li>)")
我们便可以得到⼀个正则表达式对象regular expression object,通过这个对象我们可以进⾏相关操作.
⽐如
复制代码代码如下:
result=prog.match(string)
##这个等同于
result=re.match(r"(?<=<li>).*?(?=</li>)",string)
##但是如果这个正则需要在程序匹配多次,那么通过正则表达式对象的⽅式效率会更⾼
接下来就是查了,假设我们的html结果已经以html的格式存放在text中,那么通过
复制代码代码如下:
result_list = re.findall(r"(?<=<li>).*?(?=</li>)",text)
便可以取得所需的结果列表.
⼆.替换
使⽤正则表达式进⾏替换⾮常的灵活.
⽐如之前我在阅读Trac这个系统中wiki模块的源代码的时候,就发现其wiki语法的实现就是通过正则替换进⾏的.
在使⽤替换的时候会涉及到正则表达式中的Group分组的概念.
假设wiki语法中使⽤!表⽰转义字符即感叹号后⾯的功能性字符会原样输出,粗体的语法为
写道
'''这⾥显⽰为粗体'''
那么有正则表达式为
python正则表达式不包含复制代码代码如下:
r"(?P<bold>!?''')"
这⾥的?P<bold>是Python正则语法中的⼀部分,表⽰其后的group的名字为"bold"
下⾯是替换时的情景,其中sub函数的第⼀个参数是pattern,第⼆个参数可以是字符串也可以是函数,如果是字符串的话,那么就是将⽬标匹配的结果替换成指定的结果,⽽如果是函数,那么函数会接受⼀个match object的参数,并返回替换后的字符串,第三个参数便是源字符串.
复制代码代码如下:
result = re.sub(r"(?P<bold>!?''')", replace, line)
每当匹配到⼀个三单引号,replace函数便运⾏⼀次,可能这时候需要⼀个全局变量记录当前的三单引号是开还是闭,以便添加相应的标记.
在实际的trac wiki的实现的时候,便是这样通过⼀些标记变量,来记录某些语法标记的开闭,以决定replace函数的运⾏结果.
--------------------
⽰例
⼀. 判断字符串是否是全部⼩写
代码
复制代码代码如下:
# -*- coding: cp936 -*-
import re
s1 = 'adkkdk'
s2 = 'abc123efg'
an = re.search('^[a-z]+$', s1)
if an:
print 's1:', an.group(), '全为⼩写'
else:
print s1, "不全是⼩写!"
an = re.match('[a-z]+$', s2)
if an:
print 's2:', an.group(), '全为⼩写'
else:
print s2, "不全是⼩写!"
结果
究其因
1. 正则表达式不是python的⼀部分,利⽤时需要引⽤re模块
2. 匹配的形式为: re.search(正则表达式,带匹配字串)或re.match(正则表达式,带匹配字串)。两者区别在于后者默认以开始符(^)开始。因此,
re.search('^[a-z]+$', s1) 等价于 re.match('[a-z]+$', s2)
3. 如果匹配失败,则an = re.search('^[a-z]+$', s1)返回None
group⽤于把匹配结果分组
例如
复制代码代码如下:
import re
a = "123abc456"
print re.search("([0-9]*)([a-z]*)([0-9]*)",a).group(0) #123abc456,返回整体
print re.search("([0-9]*)([a-z]*)([0-9]*)",a).group(1) #123
print re.search("([0-9]*)([a-z]*)([0-9]*)",a).group(2) #abc
print re.search("([0-9]*)([a-z]*)([0-9]*)",a).group(3) #456
1)正则表达式中的三组括号把匹配结果分成三组
group() 同group(0)就是匹配正则表达式整体结果
group(1) 列出第⼀个括号匹配部分,group(2) 列出第⼆个括号匹配部分,group(3) 列出第三个括号匹配部分。
2)没有匹配成功的,re.search()返回None
3)当然郑则表达式中没有括号,group(1)肯定不对了。
⼆. ⾸字母缩写词扩充
具体⽰例
FEMA Federal Emergency Management Agency
IRA Irish Republican Army
DUP Democratic Unionist Party
FDA Food and Drug Administration
OLC Office of Legal Counsel
分析
缩写词 FEMA
分解为 F*** E*** M*** A***
规律 ⼤写字母 + ⼩写(⼤于等于1个)+ 空格
参考代码
复制代码代码如下:
import re
def expand_abbr(sen, abbr):
lenabbr = len(abbr)
ma = ''
for i in range(0, lenabbr):
ma += abbr[i] + "[a-z]+" + ' '
print 'ma:', ma
ma = ma.strip(' ')
p = re.search(ma, sen)
if p:
up()
else:
return ''
print expand_abbr("Welcome to Algriculture Bank China", 'ABC')
结果
问题
上⾯代码对于例⼦中的前3个是正确的,但是后⾯的两个就错了,因为⼤写字母开头的词语之间还夹杂着⼩写字母词
规律
⼤写字母 + ⼩写(⼤于等于1个)+ 空格 + [⼩写+空格](0次或1次)
参考代码
复制代码代码如下:
import re
def expand_abbr(sen, abbr):
lenabbr = len(abbr)
ma = ''
for i in range(0, lenabbr-1):
ma += abbr[i] + "[a-z]+" + ' ' + '([a-z]+ )?'
ma += abbr[lenabbr-1] + "[a-z]+"
print 'ma:', ma
ma = ma.strip(' ')
p = re.search(ma, sen)
if p:
up()
else:
return ''
print expand_abbr("Welcome to Algriculture Bank of China", 'ABC')
技巧
中间的⼩写字母集合+⼀个空格,看成⼀个整体,就加个括号。要么同时有,要么同时没有,这样需要⽤到?,匹配前⽅的整体。
三. 去掉数字中的逗号
具体⽰例
在处理⾃然语⾔时123,000,000如果以标点符号分割,就会出现问题,好好的⼀个数字就被逗号肢解了,因此可以先下⼿把数字处理⼲净(逗号去掉)。
分析
数字中经常是3个数字⼀组,之后跟⼀个逗号,因此规律为:***,***,***
正则式
[a-z]+,[a-z]?
参考代码3-1
复制代码代码如下:
import re
sen = "abc,123,456,789,mnp"
p = repile("\d+,\d+?")
for com in p.finditer(sen):
mm = up()
print "hi:", mm
print "sen_before:", sen
sen = place(mm, mm.replace(",", ""))
print "sen_back:", sen, '\n'
结果
技巧
使⽤函数finditer(string[, pos[, endpos]]) | re.finditer(pattern, string[, flags]):
搜索string,返回⼀个顺序访问每⼀个匹配结果(Match对象)的迭代器。
参考代码3-2
复制代码代码如下:
sen = "abc,123,456,789,mnp"
while 1:
mm = re.search("\d,\d", sen)
if mm:
mm = mm.group()
sen = place(mm, mm.replace(",", ""))
print sen
else:
break
结果
延伸
这样的程序针对具体问题,即数字3位⼀组,如果数字混杂与字母间,⼲掉数字间的逗号,即把“abc,123,4,789,mnp”转化
为“abc,1234789,mnp”
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论