Python笔记(21)正则表达式

一个完整的正则使用过程

#调用re模块:

In [11]: import re

# re.match(pattern, string)第一个参数是你正则的规则, 第二个参数是检测的字符串:

In [12]: a=re.match(r"redhat","redhathello")

In [13]: print a.group()  
redhat

#re.match尝试从字符串的起始位置匹配一个模式,如果不是起始位置匹配成功的话,match()就返回None:

In [14]: a=re.match(r"redhat","helloredhat")

In [16]: print a
None

# 如果没有找到匹配, 也返回None:

In [17]: a=re.match(r"redhat","hellolinux")

In [18]: print a
None

正则表达式(re=regular expression)

\d和\D

In [2]: a=re.match(r"\d","1234")

In [3]: print a.group()
1

In [5]: a=re.match(r"\D","he1234")

In [6]: print a.group()
h

\s和\S 

In [9]: a=re.match(r"\s","\th123")

In [10]: print a.group()
    #这里不是什么都没有返回,其实是返回了/t,一个table键的长度的空行

In [11]: a=re.match(r"\S","\t")

In [12]: print a
None

 \w和\W

In [17]: a=re.match(r"\w","_h1")

In [18]: print a.group()
_

In [19]: a=re.match(r"\W","*#_h1")

In [20]: print a.group()
*

 [ ]

根据[ ]的特性,下面这些都可以是等价的:

[0123456789] = \d = [0-9]
[^0123456789] = \D = [^0-9]
[a-zA-Z0-9_] = \w
[^a-zA-Z0-9_] = \W
[\n\t\r] = \s
[^\n\t\r] = \S

*

#代表a字符出现0次或多次

#match方法结果实际是函数,所以如果返回一个函数也能说明匹配成功了,如下就是成功匹配字符a在" "字符串中出现0次或多次

In [67]: re.match(r"a*","hello")
Out[67]: <_sre.SRE_Match at 0xfe6098>

In [68]: re.match(r"a*"," ") Out[68]: <_sre.SRE_Match at 0xfca920>

+

#代表a字符至少出现1次

In [72]: print re.match(r"a+","hello")
None
In [75]: print re.match(r"a+","aahello")
<_sre.SRE_Match object at 0xfcad98>

练习1:匹配电话号码

需求:区号010-七位数字,中间“-”可以省略

#coding:utf-8
import re
reg=r"010-?\d{7}$"
#匹配010开头的,-可以出现1次或0次,单个数字出现7次并以这7位数字结尾
phones=["010-1234567", "0101234567", "010123","010-a123333"]
for i in phones:
    a=re.match(reg,i)
    if a:
        print "%s 合法" %(a.group())
    else:
        print "%s 不合法" %(i)
#group方法只会打印出符和条件的内容,因此这里直接打印列表中的元素

执行结果:

练习2:匹配字符串

需求::匹配出字符串第一个字母为大写字母, 后面都是小写字母, 并且这些小写字母可有可无

#coding:utf-8
import re
s=["hello","Hello","hAlla","H","a"]
reg=r"[A-Z][a-z]*"
for i in s:
    a=re.match(reg,i)
    if a:
        print "%s 合法" %(i)
    else:
        print "%s 不合法" %(i)

执行结果:

练习3:匹配qq邮箱

找出列表中符和条件的邮箱地址, 并存储到/tmp/mail.txt文件中;邮箱地址以@qq.com结尾;
@qq.com前面的内容由字母,数字或者下划线组成, 但至少4位, 最多20位

#coding:utf-8
import re
s=["dsadsad@qq.com","123@qq.com","qwer@qq.com","zsdcf@11.com"]
def ismail_ok(x):
    reg=r"\w{4,20}@qq.com$"
    a=re.match(reg,i)
    if a:
        return True
    else:
        return False
mail=[i+"\n" for i in s if ismail_ok(i)]
#使用列表生成式,如果符合条件就输出列表中的元素加上回车字符
with open("/tmp/mail.txt","a+") as f:
    f.writelines(mail)
#由于mial列表中的元素已经自带换行了,所以这里直接用列表写入mail.txt文件中的每个元素是会自动换行的

执行结果:

|

In [5]: a=re.match(r"redhat|hello","hellohdjfhhhawreda")
In [6]: print a.group()
hello
In [9]: a=re.match(r"redhat|hello","redhathdjfhhhawreda")
In [10]: print a.group()
redhat

练习4:

匹配出0-100之间的数字, 包括1和100

#coding:utf-8
import re
s=["0","1","2","45","37","100","199","897","0.7","ab"]
reg=r"^0$|^100$|[1-9]\d?$"
#匹配0,匹配100,匹配以1-9开头任意数字结尾的
for i in s:
    a=re.match(reg,i)
    if a:
        print "%s 合法" %(i)
    else:
        print "%s 不合法" %(i)

执行结果:

groups()方法

groups以元组方式返回符合条件的分组

In [25]: a=re.match(r"(\w{4,20})@(qq.com)$","abcd@qq.com")    #这里多加了两对括号,表示元组里的内容

In [26]: a.groups()
Out[26]: ('abcd', 'qq.com')

In [31]: m = re.match(r'^(\d{3})-(\d{3,8})$', '010-12345')

In [32]: m.group(0)

Out[32]: '010-12345'

In [33]: m.group(1)

Out[33]: '010'

In [34]: m.group(2)

Out[34]: '12345'

In [35]: m.groups()

Out[35]: ('010', '12345')

匹配html语言:

普通方式(group方法)

In [35]: s="<html><h1>redhat</h1></html>"

In [36]: reg=r"<\w+><\w+>\w+</\w+></\w+>"

In [37]: a=re.match(reg,s)

In [38]: a.group()

Out[38]: '<html><h1>redhat</h1></html>'

元组方式(groups方法应用:返回关键字)

In [39]: s="<html><h1>redhat</h1></html>"

In [40]: reg=r"<(\w+)><(\w+)>(\w+)</\2></\1>"

#这里给每个匹配到的组加括号表示元组中的一个元素,后面的2和1可以代替前面已经匹配到的第二个\w和第一个\w

In [41]: a=re.match(reg,s)

In [42]: a.groups()

Out[42]: ('html', 'h1', 'redhat')

In [43]: a.group()

Out[43]: '<html><h1>redhat</h1></html>'

匹配网址:

元组方式(groups方法应用:返回网址中的jishu和book关键字)

In [44]: s="http://www.redhat.org/jishu/book"

In [45]: reg=r"http://.+/(\w+)/(\w+)$"  #.表示匹配除了换行符"\n"之外的所有字符

#这里可以将想要匹配的关键字加括号,然后groups方法返回的元组中就会将这两个加括号的字符串作为元素

In [46]: a=re.match(reg,s)

In [47]: a.groups()

Out[47]: ('jishu', 'book')

In [48]: a.group()

Out[48]: 'http://www.redhat.org/jishu/book'

groupdict()方法

以字典方式返回符合条件的分组

In [52]: s="http://www.redhat.org/jishu/book"

In [53]: reg=r"http://.+/(?P<first_content>\w+)/(?P<second_content>\w+)$"

#以字典返回就必须加上一个key值,格式?P<>

In [54]: a=re.match(reg,s)

In [55]: a.groupdict()

Out[55]: {'first_content': 'jishu', 'second_content': 'book'}

In [56]: a.group()

Out[56]: 'http://www.redhat.org/jishu/book'

#可以看到无论是以元组返回关键字还是字典返回关键字都是不影响group方法正常使用的

In [57]: a.groups()

Out[57]: ('jishu', 'book')

In [5]: s="http://www.redhat.org/jishu/book/jishu/book"

In [6]: reg=r"http://.+/(?P<first_content>\w+)/(?P<second_content>\w+)/(?P=first_content)/(?P=second_content)$"

#如果有2个一样的关键字可以,可以在第二次匹配的时候直接调从第一次匹配到的字典里面取

In [7]: a=re.match(reg,s)

In [8]: a.groupdict()

Out[8]: {'first_content': 'jishu', 'second_content': 'book'}

In [9]: a.group()

Out[9]: 'http://www.redhat.org/jishu/book/jishu/book'

re高级用法

search()方法: 只找到符和条件的第一个并返回;
findall()方法: 返回符合条件的所有内容;
sub()方法: 对符合正则的内容进行替换;
split()方法: 指定多个分隔符进行分割;

search()方法

In [43]: s= "阅读次数为1000, 转发次数为100"

In [44]: a=re.search(r"\d+",s)

In [45]: print a
<_sre.SRE_Match object at 0x2289f38>

In [46]: print a.group()
1000

findall()方法

In [43]: s= "阅读次数为1000, 转发次数为100"

In [46]: b=re.findall(r"\d+",s)

In [47]: print b
['1000', '100']

sub()方法

In [43]: s= "阅读次数为1000, 转发次数为100"

In [49]: c=re.sub(r"\d+","0",s)

In [50]: print c阅读次数为0, 转发次数为0

题目5:

执行脚本之后阅读次数和转发次数都加1

解答:

#coding:utf-8import re

s="阅读次数为1000, 转发次数为100"def addNum(x):

    a=int(x.group()) +1#re方法出来的是字符串,需要先转换成整形才能进行+1运算

    return str(a)

reg=r"\d+"#匹配s中的数字,至少包含一个数字的字符串print re.sub(reg,addNum,s)
#在sub()方法中调用函数不用写(),在这里s就是传入addNum函数的实参

split()方法

In [55]: s="wangzhe 18:98766"

In [56]: print re.split(r":| ",s)   #表示指定:和空格进行分隔
['wangzhe', '18', '98766']

 python贪婪和非贪婪

默认情况下python正则是贪婪模式的

In [48]: s="this is a number 111-234-22-456"

In [49]: r=re.match(r".+(\d+-\d+-\d+-\d+)",s)

#.+表示匹配至少一个任意字符,这里的括号是groups方法的应用,可以查看前面groups的介绍

In [51]: r.group(1)  

#查看第一个括号中匹配出的内容发现有两个1被.+匹配走了,只剩下了一个1,这是由于python默认的贪婪匹配导致的
Out[51]: '1-234-22-456'

非贪婪模式, 总是匹配尽可能少的字符

*, ?,+, {m,n}后面加上?, 使得贪婪模式变成非贪婪模式;

In [52]: s="this is a number 111-234-22-456"

In [53]: r=re.match(r".+?(\d+-\d+-\d+-\d+)",s)

In [54]: r.group(1)
Out[54]: '111-234-22-456'

JSON(JavaScript Object Notation)

 是一种轻量级的数据交换格式。可以将字典转换为字符串,或者将字符串转换为字典

In [7]: dic={"service":"ftp","port":22}

In [8]: print json.dumps(dic)
{"port": 22, "service": "ftp"}

In [9]: print type(json.dumps(dic))
<type 'str'>

#coding:utf-8import json

dic={

    "service":"ftp",

    "port":22

}#将字典转换为字符串

in_json=json.dumps(dic,indent=4)#indent=4表示缩进为4,这样字符串就可以和上面字典的样子一样了print in_jsonprint type(in_json)#将字符串转换为字典

out_json=json.loads(in_json)print out_jsonprint type(out_json)

执行结果:

[root@python code12]# python json_test.py 
{
"port": 22, 
"service": "ftp"
}
<type 'str'>
{u'port': 22, u'service': u'ftp'}
<type 'dict'>

题目6:

获取ip地理位置

解答:

获取位置需要调用API,这里选择淘宝的API

#coding:utf-8import urllib2
#调用urllib2模块,可用于访问网址import json

ipadd=raw_input("输入要查询的IP:")

url="http://ip.taobao.com/service/getIpInfo.php?ip=%s" %(ipadd)#模拟浏览器访问指定链接

urlres=urllib2.urlopen(url)#读取访问的链接里面的内容

res=urlres.read()#print type(res) #可以看到这个API返回的内容是字符串,显然字符串很难处理,所以转换为字典就可以方便的处理了

res_dic=json.loads(res)#淘宝的API返回的是一个字典嵌套另一个字典,所以需要取两次keyprint "IP:%s" %(res_dic["data"]["ip"])print "Country:%s" %(res_dic["data"]["country"])print "Region:%s" %(res_dic["data"]["region"])print "City:%s" %(res_dic["data"]["city"])

执行结果:

[root@python code12]# python json_ip.py 输入要查询的IP:110.65.0.124
IP:110.65.0.124
Country:中国
Region:广东省
City:广州市

参考文档:http://blog.csdn.net/gf_lvah/article/details/79034371

 总结

• re.match(p,text) :p 为正则表达式模式, text 要查找的字符串,会返回一个match 对象
• re.search(p,text) : 只要在 text 中匹配到了 p 就返回,只返回第一个匹配到的
• re.findall(p,text) :将能匹配上的全返回,会返回一个 list
• re.split(p,text) : 按照 p 匹配,并且以匹配到的字符为分隔符切割 text, 返回一个切割后的 list
• re.sub(p,s,text) : 替换,将 p 匹配到的字符替换为 s.
• pattern = re.compile(p) 先编译 p 模式,当正则表达式模式比较复杂的时候,会先编译,然后再使用

#coding:utf-8import re

mails=["aa.qq.com","redff@qq.com","21313@aa.com"]

reg = r"\w{4,20}@qq.com$"

reg=re.compile(reg)        #事先将正则匹配编译好,再一个一个去匹配,提高脚本效率for i in mails:

    a=re.match(reg,i)

    if a:

        print "%s 合法" %(i)

    else:

        print "%s 不合法" %(i)

执行结果:

[root@python code12]# python compile_test.py 
aa.qq.com 不合法
redff@qq.com 合法
21313@aa.com 不合法

练习:

基础版:有一个日志文件access.log,统计访问前十的 IP 地址和访问次数升级版:有多个日志文件access.log,统计访问前十的 IP 地址和访问次数

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值