python的正则表达式跟perl语言的很像,用来处理字符串比较方便,记一下学习笔记。
一、常用方法:
测试数据:
这里是用了个json转成str的 字符串,而不是用了个json,json直接使用正则会报错的,json的字段查找还是用可爱的 jsonpath 吧。
test_json = {
"name":"regular expression",
"id":201920192019,
"orders":{
"order1":123,
"order2":2345
},
"string":"regexp1234regexp78hjkl90",
"listarr":[
"index1=str",
[
2,
3
],
{
"jsonstr1":"jsonstrD"
}
],
"special":"'''test123‘’\"!@@%^&&*"
}
test_str = json.dumps(test_json)
print "实际测试数据应该是:
{"name": "regular expression", "id": 201920192019, "special": "'''test123\u2018\u2019\"!@@%^&&*", "orders": {"order2": 2345, "order1": 123}, "listarr": ["index1=str", [2, 3], {"jsonstr1": "jsonstrD"}], "string": "regexp1234regexp78hjkl90"}"
1、match()从“头”匹配
re.match()
匹配字符串,从字符串开始即匹配,如果字符串里有字串匹配,但是不是从头开始匹配,也认为没有找到指定模式,返回结果是空的
test_result_m = re.match(r"\"name\":",test_str)
print test_result_m
# re.match输出结果:None,因为匹配开头,所以没有找到匹配结果
test_result_m2 = re.match(r"{\"name\":",test_str)
print test_result_m2,test_result_m2.group()
# re.match输出结果:<_sre.SRE_Match object at 0x0000000002F1B9F0> {"name":在内存0x000000000306D988这个位置找到了 {"name": 字段
补充说明:通过match和search方法获取的字符串放在一个group里,可以直接使用group()查看,如果直接打印match或者search的返回内容,实际含义是找到字段的第一个位置
2、search()“整个”匹配
re.search()
匹配字符串,不要求从开头匹配,会匹配整个字符串,直到找到第一个或者最后都没有找到结束
test_result_s = re.search(r"\"name\":",test_str)
print test_result_s,test_result_s.group()
# 直接输出re.search结果:<_sre.SRE_Match object at 0x00000000031009F0> "name":
# 这里说明在内存0x00000000031009F0这个位置找到了 "name": 字段;打印分组内容是最终结果
3、findall()找到所有
re.findall()
,匹配整个字符串,找到所有匹配模式的字串,并存放在一个list里面
test_result_f = re.findall(r"23",test_str)
print test_result_f,type(test_result_f)
# 直接输出re.findall结果:['23', '23', '23', '23'] <type 'list'>
# 找到了所有匹配模式的字串,并存放在list里面
4、sub()查找替换
re.sub(regexp,substrnew,strsource,n)
匹配字串并进行替换,可以指定替换次数n
test_result_sub = re.sub(r"23","TWOTHREE",test_str)
test_result_sub1 = re.sub(r"23","TWOTHREE",test_str,2)
print test_result_sub,"\n",test_result_sub1
# test_result_sub打印结果:{"name": "regular expression", "id": 201920192019, "special": "'''test1TWOTHREE\u2018\u2019\"!@@%^&&*", "orders": {"order2": TWOTHREE45, "order1": 1TWOTHREE}, "listarr": ["index1=str", [2, 3], {"jsonstr1": "jsonstrD"}], "string": "regexp1TWOTHREE4regexp78hjkl90"}
# 没有填写替换最大次数,默认是全部替换
# test_result_sub1输出结果:{"name": "regular expression", "id": 201920192019, "special": "'''test1TWOTHREE\u2018\u2019\"!@@%^&&*", "orders": {"order2": TWOTHREE45, "order1": 123}, "listarr": ["index1=str", [2, 3], {"jsonstr1": "jsonstrD"}], "string": "regexp1234regexp78hjkl90"}
# 指定替换个数=2后,只替换了从字符串开始匹配的前2个
5、re.split()从“中”切割
re.split(regexp, string, max)
用来分割字符串,将string按照regexp的要求进行分割,max会指定最大分割次数,默认全部分割
二、常用匹配模式:
测试数据:
str = "we12890zxcvbnm1234 567\n[]\n23456asddvnjkl7890\nasdddd1234567a\nsd"
print str
# 打印str的样子:
we12890zxcvbnm1234 567
[]
23456vnjkl7890
asdddd1234567a
sd
1、.
、.*
与.+
.
会匹配除 \n 以外的任意字符;单独用.
的时候代表1个任意字符,.*
代表可以匹配0-n个.
代表的任意字符,.+
代表可以匹配1-n个.
代表的任意字符
# .会匹配除\n意外的任意字符,单独用.的时候代表1个字符;.*代表可以匹配0-n个.代表的字符,.+代表可以匹配1-n个.代表的字符
print re.findall(r"(\d+).",str)
print re.findall(r"(\d*).",str)
print re.findall(r"(\d.*).",str)
print re.findall(r"(.\d.*).",str)
print re.findall(r"(.*\d.*).",str)
print re.findall(r"(.+\d.+).",str)
# 当然,*和+也可以与某个表达式/模式一起用,匹配多个表达式
print re.findall(r"(\d.)+.",str)
# 匹配结果
['12890', '1234', '56', '23456', '789', '1234567']
# (\d*). 需要后面有内容的0-n个数字内容,且不包含\n字符,所以匹配结果有空值(0个数字)
['', '', '12890', '', '', '', '', '', '', '1234', '56', '', '', '23456', '', '', '', '', '', '', '', '', '789', '', '', '', '', '', '', '1234567', '', '']
['12890zxcvbnm1234 56', '23456asddvnjkl789', '1234567']
['e12890zxcvbnm1234 56', '23456asddvnjkl789', 'd1234567']
['we12890zxcvbnm1234 56', '23456asddvnjkl789', 'asdddd1234567']
['we12890zxcvbnm1234 56', '23456asddvnjkl789', 'asdddd1234567']
['0z', '34', '56', '6a', '78', '56']
2、re.M
与re.S
()
可以进行多个匹配,re.M
可进行多行匹配,re.S
可以实现包括 \n 在内的多行匹配
# 多行匹配,但是不能越过\n
print re.findall(r"(567.*)",str,re.M)
# .默认不越过\n,re.S使.能够越过\n{}
print re.findall(r"(567.*)",str,re.S)
# 匹配非字母数字及下划线
print re.findall(r"\W(.*)",str)
# 匹配字母数字及下划线
print re.findall(r"\w(.*)",str)
# 取两组,最终结果每个list的一个元素是一个元组
print re.findall(r"(.*)\w(.*)",str)
# 输出结果:
['567', '567a']
['567\n[]\n23456asddvnjkl7890\nasdddd1234567a\nsd']
['567', '[]', '23456asddvnjkl7890', 'asdddd1234567a', 'sd']
['e12890zxcvbnm1234 567', '3456asddvnjkl7890', 'sdddd1234567a', 'd']
[('we12890zxcvbnm1234 56', ''), ('23456asddvnjkl789', ''), ('asdddd1234567', ''), ('s', '')]
3、[]
与[^]
[]
完成字符的精确匹配,[^…]匹配除了…以外的字符
# ['dd', 'dd'] 精确匹配2个d的字串
print re.findall(r"(d{2}).+",str)
# {n}精确匹配前面表达式n个连续的形式
print re.findall(r"(\d{2})",str)
# 匹配除数字以外的字符
print re.findall(r"([^(\d)])",str)
# 输出结果:
['dd', 'dd']
['12', '89', '12', '34', '56', '23', '45', '78', '90', '12', '34', '56']
['w', 'e', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ' ', '\n', '[', ']', '\n', 'a', 's', 'd', 'd', 'v', 'n', 'j', 'k', 'l', '\n', 'a', 's', 'd', 'd', 'd', 'd', 'a', '\n', 's', 'd']
4、贪婪匹配
贪婪匹配——匹配的越多越好,我们上面的例子默认使用的都是贪婪模式,在匹配模式末尾加上?
表示使用非贪婪模式
print re.findall(r"dd+?",str)
print re.findall(r"dd+",str)
输出结果:
['dd', 'dd', 'dd']
['dd', 'dddd']
.
为什么在使用匹配模式的时候,总是看到正则以
r
开头?
因为r
表示匹配原生字符串,在运行的时候不需要处理\
转义字符# 举个栗子: str_r = "\\asdfgh\\\"12345asd\\\rfgh" print re.findall(r"\\",str_r) # 取原生的\\,表示用了转义的\,因为\\在原始字符串中就表示用了转义的\ print re.findall("\\\\",str_r) # 没有用原生字串,首先\\\\给python解析转义成\\,然后正则表达式再解析认为是转义后的\ # 尝试的话会发现,模式开头不用 r 的话,"\\" 会报错 # 输出结果: ['\\', '\\', '\\'] ['\\', '\\', '\\']