目录
1.re模块除了能够完成使用正则表达式来匹配字符串,还可以匹配单字符
2.原生字符串
3.匹配多个字符的相关格式
4.限定匹配的边界
5.还有一些匹配分组
6.re模块的高级用法
7.group与groups
8.python的贪婪和非贪婪
正则表达式使用单个字符串来描述、匹配一系列匹配某个句法规则的字符串。
import re
#result=re.match(正则表达式,要匹配的字符串) #若匹配,返回匹配对象,否则返回None
#result.group() #用来返回字符串的匹配部分
#re.match()能够匹配以XXX开头的字符串
result=re.match("itcast","itcast.cn") #re模块匹配
print(result.group()) #返回itcast
#r1=re.match("abc","def")
#r1.group() #匹配不上,返回none
#r2=re.match("abc","abcde")
#r2.group() #正确,返回abc
#r3=re.match("abc","deabc")
#r3.group() #错误,只能匹配以abc开头的
#coding=utf-8
import re
#re.match()能够匹配以XXX开头的字符串
result=re.match(".","itcast.cn") #.可以匹配任意1个字符(除了\n)
print(result.group()) #i
r1=re.match("[hH]","Hello python") #[]可以匹配以h或H开头的字符
print(r1.group()) #H
r2=re.match("[0-9]","45hello")
print(r2.group()) #4
#r3=re.match("阳历\d号","阳历19号了")
r3=re.match("\d","19号了")
print(r3.group()) #1 我的这里不能匹配汉字,只能匹配字符串
与大多数编程语语言相同,正则表达式里使用”\“作为转义字符,这就可能造成反斜杠困扰。假如你需要匹配本中的字符”\“,那么使用编程语言表示的正则表达式里将需要4个反斜杠”\\“:前两个和后两个分别.于在编程语言转义成反斜杠,转换成两个反斜杠后再在正则表达式里转义成一个反斜杠。Python里的原生字符串很好地解决了这个问题,有了原始字符串,你再也不用担心是不是漏写了反斜杠,写出来的表达式也更直观。
python中字符串前面加上 r 表示原生字符串
#coding=utf-8
import re
#re.match()能够匹配以XXX开头的字符串
r1=re.match("c:\\\\a","c:\\a") #.可以匹配任意1个字符(除了\n)
print(r1.group()) #c:\a
#python中字符串前面加上 r 表示原生字符串
r2=re.match(r"c:\\a","c:\\a") #.可以匹配任意1个字符(除了\n)
print(r2.group()) #c:\a
#coding=utf-8
import re
r1=re.match("[A-Z][a-z]*","AbcdeFgh") #表示匹配的第一个是大写,接下来的小写可以是0到无限次
print(r1.group()) #Abcde
r2=re.match("[A-Za-z_]+[\w_]*","Ab_cde") #表示匹配的A-Z/a-z/_格式出现1到无数次,然后又出现0到无数次
print(r2.group()) #Ab_cde
r3=re.match("[A-Za-z_]+[\w_]*","_Abcde")
print(r3.group()) #_Abcde
r4=re.match("[A-Za-z_]+[\w_]*","5_Abcde")
#print(r4.group()) #匹配不成功
r5=re.match("[A-Za-z_]?[\d]*","5_Abcde") #表示匹配的A-Z/a-z/_格式出现0或1次,然后匹配数字0-9
print(r5.group()) #5
r6=re.match("[1-9]?[0-9]","28") #表示匹配的十位数上有0或1位,用来匹配0-99之间的数字
print(r6.group()) #28
r7=re.match("[1-9]?[0-9]","09") #表示匹配的十位数上有0或1位,用来匹配0-99之间的数字
print(r7.group()) #0
r8=re.match("[A-Za-z_0-9]{9,18}","1abcd6780_jio0lkujiu888") #表示匹配的9到18位的密码,每一位可以是大小写、数字、下划线
print(r8.group()) #1abcd6780_jio0lkuj 若超出18位,则只显示前18位
r9=re.match("[A-Za-z_0-9]{9,18}","1abcd8900") #表示匹配的9到18位的密码,每一位可以是大小写、数字、下划线
print(r9.group()) #1abcd6780_jio0lkuj 若不足9位,则报错
r10=re.match("[A-Za-z_0-9]{9}","1abcd89000") #表示匹配的9位的密码,每一位可以是大小写、数字、下划线
print(r10.group()) #1abcd8900 若不足9位,则报错,超出则只显示前9位
#coding=utf-8
import re
#例子:匹配163.com的邮箱 $限定边界
r1=re.match("[\w]{8,10}@163\.com$","[email protected]") #$表示匹配的必须以@163.com结尾
print(r1.group()) #[email protected]
r2=re.match("[\w]{8,10}@163.com$","[email protected]") #$表示匹配的必须以@163.com结尾
print(r2.group()) #[email protected]
r3=re.match("^[_][\w]{8,10}@163.com$","[email protected]") #^表示必须以_为开头 $表示必须以@163.com结尾
print(r3.group()) #[email protected]
r4=re.match(r".*\bis\b","time is a thief") #b表示必须以is为边界
print(r4.group()) #time is
r5=re.match(r".*\bis\b","time isnot a thief")
#print(r5.group()) #error
r6=re.match(r".*\Bis\B","timeisnot a thief") #B表示必须不以is为边界
print(r6.group()) #timeis
#coding=utf-8
import re
#例子:匹配163.com的邮箱 $限定边界
r1=re.match(r"<(\w*)><(\w*)>.*\2>\1>","www.ab.cn ") #163|qq|gmail表示中间的域名可以是任意一个
print(r1.group()) #www.ab.cn
#\2表示第二个元素,\1表示第一个元素
r2=re.match(r"<(\w*)><(\w*)>.*\2>\1>","www.ab.cn ") #163|qq|gmail表示中间的域名可以是任意一个
#print(r2.group()) #www.ab.cn #由于html与htm不一致,则无法进行匹配
#当以上面方法对逐个元素进行匹配时,按序号容易出错,所以提出下面的命名方法
#其中字母(?P)和(?P=name)中的P大写
r3=re.match(r"<(?P\w*)><(?P\w*)>.*(?P=key2)>(?P=key1)>","www.ab.cn ") #163|qq|gmail表示中间的域名可以是任意一个
print(r3.group()) #www.ab.cn
#coding=utf-8
import re
#search 匹配相应项
r1=re.search(r"\d+","访问总次数超过10000,阅读次数超过99999")
print(r1.group()) #10000
#findall 统计所有满足的项
r2=re.findall(r"\d+","访问总次数超过10000,阅读次数超过99999")
print(r2) #['10000', '99999']次数r2是列表形式,故不能再用上面方式打印
#sub 将匹配到的数据进行替换
#方法一:re.sub("要替换哪些项","要替换成什么量","替换项所在语句")
r3=re.sub(r"\d+","888888","访问总次数超过10000,阅读次数超过99999")
print(r3) #访问总次数超过888888,阅读次数超过888888
#方法二:re.sub("要替换哪些项",替换函数,"替换项所在语句")
def add(temp):
strnum=temp.group()
num=int(strnum)+5
return str(num)
r4=re.sub(r"\d+",add,"访问总次数超过10000,阅读次数超过99999")
print(r4) #访问总次数超过10005,阅读次数超过100004
#split根据匹配进行切割字符串,并返回一个列表
r5=re.split(r":| ","message:xiaozhang 29 shanxi") #:后,以空格划分
#r5=re.split(r" ","message:xiaozhang 29 shanxi") #以空格划分
print(r5) #['message', 'xiaozhang', '29', 'shanxi']
#coding=utf-8
import re
#group与groups的用法
r1=re.match(r"([^-]*)-(\d+)","010-12345678")
#r1=re.match(r"([\d]*)-(\d+)","010-12345678") #与上面写法均可
print(r1.group()) #010-12345678
print(r1.groups()) #('010', '12345678')
print(r1.group(1)) #010
print(r1.group(2)) #12345678
#print(r1.group(3)) #no such group
print(r1.groups(1)) #('010', '12345678')
print(r1.groups(2)) #('010', '12345678')
print(r1.groups(3)) #('010', '12345678')
python里数量词默认是贪婪的(在少数语言里也可能是默认非贪婪),总是尝试匹配尽可能多的字符;非贪婪则相反,总是尝试匹配尽可能少的字符。在”*“,”?“,”+“,”{m,n}“后面加上?,使贪婪变成非贪婪。
#coding=utf-8
import re
s="This is a number 234-235-22-423"
r1=re.match(".+(\d+-\d+-\d+-\d+)",s) #默认是贪婪模式
print(r1.group()) #This is a number 234-235-22-423
print(r1.group(1)) #4-235-22-423
#“.+”会从字符串的启始处抓取满⾜模式的最⻓字符,其中包括我们想得到的第⼀个整型字段的中的⼤
#部分,“\d+”只需⼀位字符就可以匹配,所以它匹配了数字“4”,⽽“.+”则匹配了从字符串起始到
# 这个第⼀位数字4之前的所有字符。
r2=re.match(".+?(\d+-\d+-\d+-\d+)",s) #添上?,表示设置为非贪婪模式
print(r2.group()) #This is a number 234-235-22-423
print(r2.group(1)) #234-235-22-423
r3=re.match(r"aa(\d+)","aa2343ddd")
r4=re.match(r"aa(\d+?)","aa2343ddd")
r5=re.match(r"aa(\d+)ddd","aa2343ddd")
r6=re.match(r"aa(\d+?)ddd","aa2343ddd")
print(r3.group(1)) #2343
print(r4.group(1)) #2
print(r5.group(1)) #2343
print(r6.group(1)) #2343
https://blog.csdn.net/lxcnn/article/details/4756030 (很棒的博客)
还可参考:
https://blog.csdn.net/wenhai_dai/article/details/52877978
http://www.runoob.com/regexp/regexp-tutorial.html
#yu:参考上面正则表达式,解决series下的日期识别问题
import numpy as np
import pandas as pd
import re
'''
#邮箱识别实例
data1=pd.Series({'li':'[email protected]', 'wang':'[email protected]', 'chen':'[email protected]', 'zhao':'[email protected]', 'sun':'[email protected]'})
pattern1 = re.compile(r'(\d*)@([a-z]+)\.([a-z]{2,4})')
result1=data1.str.match(pattern1)
print(result1)
print(data1.str.extract(pattern1,expand=True)) #匹配不上的会用nan代替
'''
#日期书写不规范识别实例
d1=pd.Series({'1':'生产日期:2017年3月26日 0:00:00','2':'2017/4/13', '3':'2017年10.3','4':'生产日期:2017年03月26日', '5':'2016//9//25',
'6':'2017-08-06购进','7':'20170112','8':'购进日期2016年12月14日/20160726','9':'2017-07-23/20170723B','10':'2017/72','11':'/'})
print(d1)
pattern=re.compile(r".*?(\d{4}).*?(\d{1,2}).*?(\d{1,2}).*")
result=d1.str.match(pattern)
#print(d1.str.extractall(pattern)) #只返回匹配成功的
print(d1.str.extract(pattern,expand=True)) #匹配不上的会用nan代替
'''
1 生产日期:2017年3月26日 0:00:00
10 2017/72
11 /
2 2017/4/13
3 2017年10.3
4 生产日期:2017年03月26日
5 2016//9//25
6 2017-08-06购进
7 20170112
8 购进日期2016年12月14日/20160726
9 2017-07-23/20170723B
dtype: object
0 1 2
1 2017 3 26
10 2017 7 2
11 NaN NaN NaN
2 2017 4 13
3 2017 10 3
4 2017 03 26
5 2016 9 25
6 2017 08 06
7 2017 01 12
8 2016 12 14
9 2017 07 23
'''
注:
"""
"""表示可以保留字符串的原始格式,包括里面的换行、引号之类的,会在内存值存储,文件过大也会影响执行效率,而#表示遇见就直接跳过,所以引号注释不等于#注释
多行注释:ctrl+/