python 分组匹配_Python 基础之正则之二 匹配分组,正则相关函数及表达式修饰符...

四.匹配分组

[元字符]分组符号

a|b   匹配字符a或 字符b  (如果两个当中有重合部分,把更长的那个放前面)

(ab)   匹配括号内的表达式 ,将()作为一个分组

num  引用分组num匹配到的字符串

(?P)给分组命名

(?P=name)引用别名: 把name分组所匹配到的内容引用到这里

1.正常分组 ()

## (1) 正常情况下用()圆括号进行分组 可以用\1反向引用第一个圆括号匹配的内容。

## (2) (?:正则表达式)表示取消优先显示的功能

(正则表达式)把分组的匹配到的内容加到列表,不是分组的匹配匹配到的内容不加到列表中(?:正则表达式)把分组的匹配到的内容和没有分组匹配到的内容一起加到列表里

print(re.findall('.*?_good', 'one_good two_good three_good'))

# 注意从头开始的,然后进行匹配,匹配搭配_good开始不是任意字符

# ['one_good', ' two_good', ' three_good']

print(re.findall('(.*?)_good', 'one_good two_good three_good'))

# ['one', ' two', ' three']

# 在匹配的时候是需要_good才能符合匹配条件的,但是并没有加到列表中

# 只把分组匹配搭配的内容加入到列表中

print(re.findall('(?:.*?)_good', 'one_good two_good three_good'))

# 将匹配到的内容全部加到列表中,不管是分组内的还是分组外的

# ['one_good', ' two_good', ' three_good']

## (3)| 代表或

# 既想匹配abc 还要匹配 abcd

lst = re.findall("abc|abcd", "abc234abcd234390dbohdq")

print(lst)

# 有缺陷,不能够都匹配到

# ['abc', 'abc']

lst = re.findall("abcd|abc", "abc234abcd234390dbohdq")

print(lst)

# ['abc', 'abcd']

#对.匹配进行解析用\让原本有意义的字符变得无意义.代表任意字符,除了\n如果想要让正则匹配有个用\.让点的转义失效

# 匹配小数

# 231.321 3213 312 89.32 0.3231

lst = re.findall("\d+\.\d+", "231.321 3213 312 89.32 0.3231")

# \d+ 表示匹配一个或者多个数字

print(lst)

# ['231.321', '89.32', '0.3231']

# 使用分组的形式来匹配小数和正数

# 不正确版本,加入的是小数部分或空字符

lst = re.findall("\d+(\.\d+)?", "231.321 3213 312 89.32 0.3231")

print(lst)

# ['.321', '', '', '.32', '.3231']

# 正确版

lst = re.findall("\d+(?:\.\d+)?", "231.321 3213 312 89.32 0.3231")

print(lst)

# ['231.321', '3213', '312', '89.32', '0.3231']

# 从字符串中匹配135或171的手机号

print("=========================135")

lst = re.findall("(?:135|171)\d{8}", "135678987654w171skdjfksjkf 11312312317178787887")

print(lst)

lst = re.findall("135\d{8}|171\d{8}", "135678987654w171skdjfksjkf 11312312317178787887")

print(lst)

lst = re.findall("(?:135|171)[0-9]{8}", "135678987654w171skdjfksjkf 11312312317178787887")

print(lst)

# 结果都是:

# ['13567898765', '17178787887']

2.命名分组

## (3) (?P正则表达式)给这个组起一个名字## (4) (?P=组名)引用之前组的名字,把该组名匹配到的内容放到当前位置

import re

#首先是正常分组对这些内容的匹配及结果

strvar = '

sdfsdfsdfsdf

'

lst = re.findall("(.*?)",strvar)

print(lst)

# [('h1', 'sdfsdfsdfsdf', '/h1')]

strvar = "123

sdfsdfsdfsdf

 123

ppoo

"

lst = re.findall("(.*?)",strvar)

print(lst)

# [('h1', 'sdfsdfsdfsdf', '/h1'), ('h2', 'ppoo', '/h2')]

#反向引用,#拿到已经匹配到的值,再引用一次#引用第一个口号里面的内容\1#引用第二个括号里面的内容\2依次类推

#例:

strvar = "123

sdfsdfsdfsdf

 123

ppoo

"

lst = re.findall(r"(.*?)\1>",strvar)

print(lst)

#findall能根据反向匹配,但是不显示在匹配后的数据里

# [('h1', 'sdfsdfsdfsdf'), ('h2', 'ppoo')]

#命名分组方式1:

strvar = 'd3j5sdj'

obj = re.search(r"(.*?)\d(.*?)\d(.*?)\1\2",strvar)

print(obj)

# <_sre.sre_match object span="(0," match="d3j5sdj">

res = obj.group()  #对象.方法

print(res)

#search反向引用的数据也匹配到数据中,关于search说明请见正则相关函数

# 结果为: d3j5sdj

#命名分组方式2:

#用命名分组进行反向引用

obj = re.search("(?P.*?)\d(?P.*?)\d(?P.*?)(?P=tag1)(?P=tag2)",strvar)

print(obj)

# 得到的是一个对象: <_sre.sre_match object span="(0," match="d3j5sdj">

res = obj.group()

# 使用对象.方法 的到数据: d3j5sdj

print(res)

#命名分组方式3:

obj = re.search(r"(?P.*?)\d(?P.*?)\d(?P.*?)\1\2",strvar)

print(obj)

# <_sre.sre_match object span="(0," match="d3j5sdj">

res = obj.group()

print(res)

# 使用对象.方法 的到数据: d3j5sdj

五.正则相关函数

findall  匹配字符串中相应内容,返回列表[用法: findall("正则表达式","要匹配的字符串")]

search   通过正则匹配出第一个对象返回,通过group取出对象中的值

match    验证用户输入内容

split    切割

sub      替换

finditer 匹配字符串中相应内容,返回迭代器

compile  指定一个统一的匹配规则

1.findall

上面已经讲过不多做讲解

2.search

通过正则匹配出第一个对象返回,通过group取出对象中的值

Search通过正则匹配出第一个对象返回(只匹配一次),通过group取出对象中的值

findall把满足条件的所有值都找出来放到列表里面返回search找到一个满足条件的值就直接返回,扔到一个对象当中想要获取对象中的值,用group对象.group()

# 注意只匹配一次

obj = re.search("\d+", "dohd3093dhdoqhd9023")

# \d+ 表示匹配多次数字,到不符合停止,search只匹配一次所有是3093

print(obj)  # 返回的是一个对象 #<_sre.sre_match object span="(4," match="3093">

res = obj.group()

print(res)  # 3093

# 匹配www.baidu.com 或者 www.sohu.com

obj = re.search("(w{3})\.(baidu|sohu)\.(com)", "www.baidu.com www.sohu.com")

res = obj.group()

#虽然两个地址都符合条件,但是search只匹配一次

print(res)

#结果: www.baidu.com

obj = re.search("(www)\.(baidu|sohu)\.(com)", "www.sohu.com")

res = obj.group()

print(res) # www.sohu.com

# 数字1 代表第一个括号里面的内容

res = obj.group(1)

print(res)  # www

# 数字2 代表第二个括号里面的内容

res = obj.group(2)

print(res)  # sohu

# 数字2 代表第三个括号里面的内容

res = obj.group(3)

print(res) # com

# groups 一次性把所有小括号里面的内容匹配出来

res = obj.groups()

print(res) # ('www', 'sohu', 'com')

3.match验证用户输入内容

# search 和 match 用法一样,区别在于match 在正则的前面加了一个^条件 [必须以...开头]

# search 只需要在正则的前面加上^ 就可以取代 match

strvar = "uuyydfopopopop3434sdf234"

# obj = re.search("^d.*?",strvar)  #等价于,match

obj = re.search("d.*?\d", strvar)

res = obj.group()

print(res) # dfopopopop3

# match

obj = re.match("d.*?\d", strvar)

print(obj)  # None 必须以d作为字符串的开头,所有匹配不到返回None

# res = obj.group()

# print(res)

4.split切割

#例1:

#字符串的方法是将,替换成| 再用字符串切割用| 切割为列表

strvar = "one|two|three,four"

lst = strvar.replace(",","|").split("|")

print(lst)

#['one', 'two', 'three', 'four']

#使用re的切割方法

strvar = "one,two|three%four"

res = re.split(r"[,|%]",strvar)

#通过多个字符选一个匹配切割最后得到列表

print(res)

#['one', 'two', 'three', 'four']

#例2:

strvar = "one234234two2three909090four"

res = re.split(r"\d+",strvar)

# 通过用\d+ 为分界来切割,将得到的数据返回放入列表

print(res)

# ['one', 'two', 'three', 'four']

5.sub 替换

#格式: sub(pattern, repl, string, count=0, flags=0)

#例:

strvar = "one,two|three%four"

res = re.sub("[,|%]","-",strvar)

print(res)

# one-two-three-four

#后面可以选择替换的次数

#只替换一次

res = re.sub("[,|%]","-",strvar,1)

print(res)

# one-two|three%four

res = re.sub("[,|%]","-",strvar,count=1)

print(res)

# one-two|three%four

#subn 和 sub 用法一样,最大的区别在返回值,返回一个元组,包含替换的次数

res = re.subn(r"[,|%]","-",strvar)

print(res)

# ('one-two-three-four', 3)

6.finditer匹配字符串中相应的内容,返回迭代器

# finditer 和 findall 用法一样,区别在于返回的是迭代器

strvar = "sdfsdff&*&*%^%234sdfsdfskdjfk3sdf23"

#例:使用findall

lst = re.findall("\d", strvar)

print(lst) # ['2', '3', '4', '3', '2', '3']

#例:使用finditer

res = re.finditer("\d", strvar)

print(res) #

from collections import Iterator

print(isinstance(res, Iterator))  # True

it = re.finditer("\d", strvar)

#lst = list(it)

#print(lst)

obj = next(it)

res = obj.group()

print(res)

# 2

for i in it:

res = i.group()

print(res)

# 输出为: 3 4 3 2 3

7.compile  指定一个统一的匹配规则

写一套正则,程序就需要重新编译一次同一个正则多处使用,反复编译会浪费时间这样的话,就可以使用compile来定义,终身受益

#例:

rule = re.compile("\d+") #规则是匹配至少一次数字

print(rule) # re.compile('\\d+')

strvar = "sdfsdfs234kjkjk*(*9343dsf3"

# 用search 匹配至少一次数字贪婪算法知道不符合才停止

obj = rule.search(strvar)

# 获取一个对象

print(obj) # <_sre.sre_match object span="(7," match="234">

# 对象.方法得到数据

print(obj.group()) # 234

#使用规则用findall进行匹配

lst = rule.findall(strvar)

# ['234', '9343', '3']

print(lst)

六.正则表达式修饰符

常用修饰符说明:

re.I使匹配对大小写不敏感

re.M多行匹配,影响 ^ 和$

re.S使 . 匹配包括换行在内的所有字符

#例1:

strvar =  """

sdfsf

dd22

aabb

"""

# 不受大小写影响,和不受换行影响结合

lst = re.findall("^

(.*?)

$",strvar,flags=re.M|re.I)

print(lst) # ['sdfsf', 'dd22', 'aabb']

#例2:

strvar = """

sdfsf

dd22

aabb

"""

#不受多行匹配影响

rule = re.compile("^

(.*?)

$",flags=re.M)

#rule = re.compile("^

(.*?)

$",flags=re.M|re.I)

lst = rule.findall(strvar)

print(lst)

print("===========")

#re.S 使.匹配包括换行在内的所有字符

obj = rule.search(strvar)

print(obj.group())

正则相关练习

import re

# 1、匹配整数或者小数(包括正数和负数)

lst = re.findall(r"[+-]*?\d+\.*?\d*?",'-555555 w3213 +321 321.321 321.321')

print(lst)

# 2、匹配年月日日期 格式 2018-12-31

lst = re.findall( '\d{4}-(?:0[0-9])-(?:[0-2]\d)|\d{4}-(?:0[0-9])-

(?:[3][0-1])|\d{4}-(?:1[0-2])-(?:[0-2]\d)|\d{4}-(?:1[0-2])-(?:[3][0-1])','2018-12-31 2018-09-02 2018-02-29 2018-10-31 qwhowq3056-13-24 2018-01-32')

print(lst)

# 3、匹配qq号 5-12 首字符没有0

import re

qqnum = input("请输入您的qq号:")

lst = re.findall('^[1-9]\d{4,11}$',qqnum)

if len(lst) == 0:

print("您输入的qq号格式有错误")

else:

print("您的qq号为:",lst[0])

# 4、11位的电话号码

import re

call_num = input("请输入您的电话号码:")

lst = re.findall("^[1-9]\d{10}$",call_num)

if len(lst) == 0:

print("您输入的手机号有误")

else:

print("您输入的电话号码是:",lst[0])

# 5、长度为8-10位的用户密码 : 包含数字字母下划线

import re

lst = re.findall('[\da-zA-Z_]{8,10}','js_28aAA')

print(lst)

# 6 写出4位验证码的正则匹配

import re

lst = re.findall('[\da-zA-Z]{4}','fF4n 1231 312313  dads12   123 d a ddd')

print(lst)

# 7、匹配邮箱地址 邮箱规则

# @之前必须有内容且只能是字母(大小写)、数字、下划线(_)、减号(-)、点(.)

# @和最后一个点(.)之间必须有内容且只能是字母(大小写)、数字、点(.)、减号(-),且两个点不能挨着

# 最后一个点(.)之后必须有内容且内容只能是字母(大小写)、数字且长度为大于等于2个字节,小于等于6个字节

import re

lst = re.findall(r'[a-zA-Z\d\-\_\.]+@[a-zA-Z\d\.\-]+\.[a-zA-Z]{2,6}','[email protected] [email protected] [email protected]')

print(lst)

import re

# 8、从类似

# wahaha

# banana

#

qqxing

#

q

# 这样的字符串中,

# 1)匹配出 wahaha,banana,qqxing 内容。

"

(.*?)

"

"""

import re

strvar = "

qqxing

banana"

lst = re.findall("<.>(.*?)<.>",strvar)

print(lst)

re.search("<.>(.*?)<.>",strvar)

"""

import re

strvar= """wahaha banana

qqxing

q

"""

lst1 = re.findall(r"<.>([^<>]{2,})<.>",strvar)

print(lst1)

# 2)匹配出 a,b,h1这样的内容

lst2 = re.findall(r"(.*?)>",strvar)

print(lst2)

lst3 = re.findall(r"",strvar)

print(lst3)

# 9.

print("========把字符串进行运算==========")

strvar = "5*6-7/3"

def suan(strvar):

strvar = strvar

lst = re.findall("(?:\d+)(?:[*/+-])(?:\d+)", strvar)

for i in lst :

obj = re.search("(\d+)([*/+-])(\d+)",i)

#res = obj.group()

#print(res)

if obj.group(2) == "*":

res = int(obj.group(1)) * int(obj.group(3))

#print(res)

elif obj.group(2) == "/":

res = int(obj.group(1)) / int(obj.group(3))

#print(res)

elif obj.group() == "+":

res = int(obj.group(1)) + int(obj.group(3))

#print(res)

elif obj.group(2) == "-":

res = int(obj.group(1)) - int(obj.group(3))

#print(res)

strvar = strvar.replace(i,str(res))

return strvar

strvar = suan(strvar)

print("=====1========")

print(strvar)

strvar = suan(strvar)

print("=====2========")

print(strvar)

# 10.计算器

import re

#计算乘除的方法

def parse_exp(exp):

if "*" in exp:

a,b = exp.split("*")

#print(a,b)

return str(float(a) * float(b))

if "/" in exp:

a,b = exp.split("/")

return str(float(a) / float(b))

#去除++ +- -- -+  bug 情况

def exp_format(exp):

#如果出现下面情况就替换相应的

exp = exp.replace("+-","-")

exp = exp.replace("--","+")

exp = exp.replace("-+","-")

exp = exp.replace("++","+")

return exp

#实际计算

def exp_calc(strvar):

#计算乘除

while True:

res_obj = re.search("\d+(\.\d+)?[*/][+-]?\d+(\.\d+)?",strvar)

if res_obj:

res = res_obj.group()

#print(res) #5*-2

res2 = parse_exp(res)

#print(res)

strvar = strvar.replace(res,res2)

else:

break

#print(strvar)

#计算加减

res = exp_format(strvar)

#print(lst)

lst = re.findall("[+-]?\d+(?:\.\d+)?",res)

#print(lst)

count = 0

for i in lst:

count += float(i)

#print(count)

return count

#去除括号

def remove_bracket(strvar):

while True:

#匹配出最里面一层的括号

res_obj = re.search("\([^()]+\)",strvar)

if res_obj:

res_exp = res_obj.group()

#print(res_exp)

#计算口号里面的值,exp_calc

res = str(exp_calc(res_exp))

#print(res,type(res))

#把算好的实际数值转换成字符串,替换以前的圆括号

strvar = strvar.replace(res_exp,res)

else:

#直接返回替换好的字符串

return strvar

#主函数

def main(strvar):

#先把所有的空格去掉

strvar = strvar.replace(" ","")

#去掉空格

res = remove_bracket(strvar)

#print(res)

#计算最后结果

return exp_calc(res)

a = '1-2*((60-30+(-40/5)*(9-2*5/3+7/3*99/4*2998+10*568/14))-(-4*3)/(16-3*2))'

res = main(a)

print(res)

#验证结果

res = eval(a)

print(res)

你可能感兴趣的:(python,分组匹配)