python正则表达式group用法_【Python】正则表达式用法

导读:正则在各语言中的使用是有差异的,本文以 Python 3 为基础。本文主要讲述的是正则的语法,对于 re 模块不做过多描述,只会对一些特殊地方做提示。

很多人觉得正则很难,在我看来,这些人一定是没有用心。其实正则很简单,根据二八原则,我们只需要懂 20% 的内容就可以解决 80% 的问题了。我曾经有几年几乎每天都跟正则打交道,刚接手项目的时候我对正则也是一无所知,花半小时百度了一下,然后写了几个 demo,就开始正式接手了。三年多时间,我用到的正则鲜有超出我最初半小时百度到的知识的。

1、正则基础

1.1、基础语法

(1)常用元字符

语法描述

\b

匹配单词的开始或结束

\d

匹配数字

\s

匹配任意不可见字符(空格、换行符、制表符等),等价于[ \f\n\r\t\v]。

\w

匹配任意 Unicode 字符集,包括字母、数字、下划线、汉字等

.

匹配除换行符(\n)以外的任意字符

^ 或 \A

匹配字符串或行的起始位置

$ 或 \Z

匹配字符串或行的结束位置

(2)限定词(又叫量词)

语法描述

*

重复零次或更多次

+

重复一次或更多次

?

重复零次或一次

{n}

重复 n 次

{n,}

重复 n 次或更多次

{n,m}

重复 n 到 m 次

(3)常用反义词

语法描述

\B

匹配非单词的开始或结束

\D

匹配非数字

\S

匹配任意可见字符, [^ \f\n\r\t\v]

\W

匹配任意非 Unicode 字符集

除 a、b、c 以外的任意字符

(4)字符族

语法描述

[abc]

a、b 或 c

除 a、b、c 以外的任意字符

[a-zA-Z]

a 到 z 或 A 到 Z

[a-d[m-p]]

a 到 d 或 m 到 p,即 [a-dm-p](并集)

[a-z&&[def]]

d、e 或 f(交集)

[a-z&&[^bc]]

a 到 z,除了 b 和 c:[ad-z](减去)

[a-z&&[^m-p]]

a 到 z,减去 m 到 p:[a-lq-z](减去)

以上便是正则的基础内容,下面来写两个例子看下:

s = '123abc你好'

re.search('\d+', s).group()

re.search('\w+', s).group()

结果:

123

123abc你好

是不是很简单?

1.2、修饰符

修饰符在各语言中也是有差异的。

Python 中的修饰符:

修饰符描述

re.A

匹配 ASCII字符类,影响 \w, \W, \b, \B, \d, \D

re.I

忽略大小写

re.L

做本地化识别匹配(这个极少极少使用)

re.M

多行匹配,影响 和

re.S

使 . 匹配包括换行符(\n)在内的所有字符

re.U

匹配 Unicode 字符集。与 re.A 相对,这是默认设置

re.X

忽略空格和 # 后面的注释以获得看起来更易懂的正则。

(1)re.A

修饰符 A 使 \w 只匹配 ASCII 字符,\W 匹配非 ASCII 字符。

s = '123abc你好'

re.search('\w+', s, re.A).group()

re.search('\W+', s, re.A).group()

结果:

123abc

你好

但是描述中还有 \d 和 \D,数字不都是 ASCII 字符吗?这是什么意思?别忘了,还有 全角和半角!

s = '0123456789'    # 全角数字

re.search('\d+', s, re.U).group()

结果:

0123456789

(2)re.M

多行匹配的模式其实也不常用,很少有一行行规整的数据。

s = 'aaa\r\nbbb\r\nccc'

re.findall('^[\s\w]*?$', s)

re.findall('^[\s\w]*?$', s, re.M)

结果:

['aaa\r\nbbb\r\nccc']        # 单行模式

['aaa\r', 'bbb\r', 'ccc']    # 多行模式

(3)re.S

这个简单,直接看个例子。

s = 'aaa\r\nbbb\r\nccc'

re.findall('^.*', s)

re.findall('^.*', s, re.S)

结果:

['aaa\r']

['aaa\r\nbbb\r\nccc']

(4)re.X

用法如下:

rc = re.compile(r"""

\d+ # 匹配数字

# 和字母

[a-zA-Z]+

""", re.X)

rc.search('123abc').group()

结果:

123abc

注意,用了 X 修饰符后,正则中的所有空格会被忽略,包括正则里面的原本有用的空格。如果正则中有需要使用空格,只能用 \s 代替。

(5)(?aiLmsux)

修饰符不仅可以代码中指定,也可以在正则中指定。(?aiLmsux) 表示了以上所有的修饰符,具体用的时候需要哪个就在 ? 后面加上对应的字母,示例如下,(?a) 和 re.A 效果是一样的:

s = '123abc你好'

re.search('(?a)\w+', s).group()

re.search('\w+', s, re.A).group()

结果是一样的:

123abc

123abc

1.3、贪婪与懒惰

当正则表达式中包含能接受重复的限定符时,通常的行为是(在使整个表达式能得到匹配的前提下)匹配尽可能多的字符。

s = 'aabab'

re.search('a.*b', s).group()    # 这就是贪婪

re.search('a.*?b', s).group()   # 这就是懒惰

结果:

aabab

aab

简单来说:

所谓贪婪,就是尽可能 多 的匹配;

所谓懒惰,就是尽可能 少 的匹配。

*、+、{n,} 这些表达式属于贪婪;

*?、+?、{n,}? 这些表达式就是懒惰(在贪婪的基础上加上 ?)。

2、正则进阶

2.1、捕获分组

语法描述

(exp)

匹配exp,并捕获文本到自动命名的组里

(?Pexp)

匹配exp,并捕获文本到名称为 name 的组里

(?:exp)

匹配exp,不捕获匹配的文本,也不给此分组分配组号

(?P=name)

匹配之前由名为 name 的组匹配的文本

注意:在其他语言或者网上的一些正则工具中,分组命名的语法是 (?exp) 或 (?'name'exp) ,但在 Python 里,这样写会报错:This named group syntax is not supported in this regex dialect。Python 中正确的写法是:(?Pexp)

示例一:

分组可以让我们用一条正则提取出多个信息,例如:

s = '姓名:张三;性别:男;电话:138123456789'

m = re.search('姓名[::](\w+).*?电话[::](\d{11})', s)

if m:

name = m.group(1)

phone = m.group(2)

print(f'name:{name}, phone:{phone}')

结果:

name:张三, phone:13812345678

示例二:

(?Pexp) 有时还是会用到的, (?P=name) 则很少情况下会用到。我想了一个 (?P=name) 的使用示例,给大家看下效果:

s = '''

张三

30

138123456789

'''

pattern = r'.*?)>(.*?)(?P=name)>'

It = re.findall(pattern, s)

结果:

[('name', '张三'), ('age', '30'), ('phone', '138123456789')]

2.2、零宽断言

语法描述

(?=exp)

匹配exp前面的位置

(?<=exp)

匹配exp后面的位置

(?!exp)

匹配后面跟的不是exp的位置

(?

匹配前面不是exp的位置

注意:正则中常用的前项界定 (?<=exp) 和前项否定界定 (?

(?<=aaa)        # 正确

(?<=aaa|bbb)    # 正确

(?<=aaa|bb)        # 错误

(?<=\d+)        # 错误

(?<=\d{3})        # 正确

2.3、条件匹配

这大概是最复杂的正则表达式了。语法如下:

语法描述

(?(id/name)yes|no)

如果指定分组存在,则匹配 yes 模式,否则匹配 no 模式

此语法极少用到,印象中只用过一次。

以下示例的要求是:如果以 _ 开头,则以字母结尾,否则以数字结尾。

s1 = '_abcd'

s2 = 'abc1'

pattern = '(_)?[a-zA-Z]+(?(1)[a-zA-Z]|\d)'

re.search(pattern, s1).group()

re.search(pattern, s2).group()

结果:

_abcd

abc1

2.4、findall

Python 中的 re.findall 是个比较特别的方法(之所以说它特别,是跟我常用的 C# 做比较,在没看注释之前我想当然的掉坑里去了)。我们看这个方法的官方注释:

Return a list of all non-overlapping matches in the string.

If one or more capturing groups are present in the pattern, return

a list of groups; this will be a list of tuples if the pattern

has more than one group.

Empty matches are included in the result.

简单来说,就是

如果没有分组,则返回整条正则匹配结果的列表;

如果有 1 个分组,则返回分组匹配到的结果的列表;

如果有多个分组,则返回分组匹配到的结果的元组的列表。

看下面的例子:

s = 'aaa123bbb456ccc'

re.findall('[a-z]+\d+', s)          # 不包含分组

re.findall('[a-z]+(\d+)', s)        # 包含一个分组

re.findall('([a-z]+(\d+))', s)      # 包含多个分组

re.findall('(?:[a-z]+(\d+))', s)    # ?: 不捕获分组匹配结果

结果:

['aaa123', 'bbb456']

['123', '456']

[('aaa123', '123'), ('bbb456', '456')]

['123', '456']

零宽断言中讲到 Python 中前项界定必须是定长的,这很不方便,但是配合 findall 有分组时只取分组结果的特性,就可以模拟出非定长前项界定的效果了。

结语

其实正则就像是一个数学公式,会背公式不一定会做题。但其实这公式一点也不难,至少比学校里学的数学简单多了,多练习几次也就会了。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值