PythonPython

Python正则表达式(二)

2020-11-29  本文已影响0人  名本无名

回顾

上节我们说到Python正则表达式的基本字符,以及这些字符的用法

今天,我们继续讲讲Python中一些扩展标记法,以及一些特殊序列

扩展标记法

(?...): 这种扩展标记法以括号内?开头,其后第一个字符决定了采用什么样的语法。

1、(?aiLmsux)

介绍

?后面添加( 'a', 'i', 'L', 'm', 's', 'u', 'x'中的一个或多个),然后加上匹配规则。

这些字符对正则表达式设置以下标记,免去设置 flag 参数

'a' ==> re.A(re.ASCII) ==> 只匹配 ASCII 字符
'i' ==> re.I(re.IGNORECASE) ==> 忽略大小写
'L' ==> re.L(re.LOCALE) ==> 由当前语言区域决定 \w, \W, \b, \B 和大小写敏感匹配,不推荐使用。
'm' ==> re.M(re.MULTILINE) ==> 多行模式
's' ==> re.S(re.DOTALL) ==> .匹配全部字符
'u' ==> re.U ==> Unicode匹配,Python3默认开启这个模式
'x' ==> re.X(re.VERBOSE) ==> 冗长模式

注意'a', 'L', 'u' 作为内联标记是相互排斥的,它们不能结合在一起

示例

# 忽略大小写
re.findall('(?i)ab', 'Ab')
# out: ['Ab']

# 连用s、i
re.findall('(?si)ab.', 'Ab\n')
# out: ['Ab']

# 多行模式
re.findall('^a.', 'ab\nac')
# out: ['ab']
re.findall('(?m)^a.', 'ab\nac')
# out: ['ab', 'ac']

# .匹配全部字符
re.findall('(?s)ab.', 'ab\n')
# out: ['ab\n']

# 冗长模式
# 这个标记允许你编写更具可读性更友好的正则表达式。
# 通过分段和添加注释,其中空白符号会被忽略
re.findall(r"""(?x)\d +  # 整数位
                \.       # 小数点
                \d *     # 小数位
                """, '3.1415na')
# out: ['3.1415']

2、(?:…)

介绍

括号分组的非捕获版本,该分组所匹配的子字符串 不能 在执行匹配后被获取或是在之后的模式中被引用

可以配合 |{m} 使用

示例

re.findall('(abc){2}', 'abcabc')
# out: ['abc']

re.findall('(?:abc){2}', 'abcabc')
# out: ['abcabc']

# 可以看出,捕获版本和非捕获版本的区别
# 捕获版本会捕获到()分组内的匹配字符
# 非捕获版本会将()分组内的字符与外面的字符作为一个整体返回
# 看一个嵌套捕获的例子
re.findall('(a(bc))cbs', 'abccbs')
# out: [('abc', 'bc')]

re.findall('(a(?:bc))cbs', 'abccbs')
# out: ['abc']

re.findall('(abc)|cbs', 'cbs')
# out: ['']

re.findall('(?:abc)|cbs', 'cbs')
# out: ['cbs']

3、(?P<name>…)(?P=name)

介绍

为分组再指定一个组合名

每个组合名只能用一个正则表达式定义,只能定义一次

反向引用一个命名组合

匹配前面那个名字叫 name 的命名组中匹配到的字符串

示例

re.findall('(?P<name>abc)\\1', 'abcabc')
re.findall('(?P<name>abc)(?P=name)', 'abcabc')
# out: ['abc']

4、(?#…)

介绍

注释信息,里面的内容会被忽略。

示例

re.findall('abc(?#这是注释)123', 'abc123')
# out: ['abc123']

5、(?=…), (?!…)

介绍

哈哈,是不是没看懂,没事,举个栗子

示例

re.findall('Isaac (?=Asimov)', 'Isaac Asimov, Isaac Ash')
# out: ['Isaac ']
# 只有后面是 'Asimov' 的时候才匹配前面的 'Isaac '

re.findall('Isaac. (?!Asimov)', 'Isaac1 Asimov, Isaac2 Ash')
# out: ['Isaac2 ']
# 为了显示区别,我们加了 '.' 匹配数字 1、2
# 从中可以看出,只有后面 不 是 'Asimov' 的时候才匹配 'Isaac ' 

看看,是不是一下子就明了了。

6、(?<=…), (?<?…)

介绍

哈哈,这个又看不懂?

思考一下,既然有根据后面字符断言的,那么根据前面字符来断言,也是很合理的,

示例

re.findall('(?<=Isaac )Asimov.', 'Isaac Asimov1, Asimov2')
# out: ['Asimov1']

re.findall('(?<!Isaac )Asimov.', 'Isaac Asimov1, Asimov2')
# out: ['Asimov2']

7、(?(id/name)yes-pattern|no-pattern)

介绍

如果给定的 idname 存在,将会尝试匹配 yes-pattern,否则就尝试匹配 no-patternno-pattern 可选,也可以被忽略。

是不是有点像if else三目运算,其中 idname 是分组 id、和指定的分组名 name

照旧,举个栗子吧

示例

re.findall('(<)?(\w+@\w+(?:\.\w+))(?(1)>|$)', '<username@host.com>')
# out: [('<', 'username@host.com')]

re.findall('(<)?(\w+@\w+(?:\.\w+))(?(1)>|$)', 'username@host.com>')
# out: []

re.findall('(<)?(\w+@\w+(?:\.\w+))(?(1)>|$)', '<username@host.com')
# out: [('', 'username@host.com')]

re.findall('(<)?(\w+@\w+(?:\.\w+))(?(1)>|$)', 'username@host.com')
# out: [('', 'username@host.com')]

看了栗子是不是有点糊涂呢,我们来解析一下这个正则表达式

其结果匹配的就是<username@host.com>username@host.com

而不会匹配 <user@host.com' 和 <user@host.com

但是上面的第三个结果为啥不一样呢?

因为findall允许返回空匹配的,在有 ?的情况下,所以它会分两种情况去匹配

特殊序列

字符描述

image.png

简单示例

re.findall('(ab)c\\1', 'abcab')
# out: ['ab']
# 注意,这里需要 \\,等同于 r'(ab)c\1'
# 为了方便,我们下面都使用 r''

re.findall(r'\Aabc', 'abccadc\nabc')
re.findall(r'^abc', 'abccadc\nabc')
# out: ['abc']
# 只有开头的 abc 匹配了

re.findall(r'\bHello\b', 'Hello world! Hellooo')
# out: ['Hello']
# 注意,通常 \b 定义为 \w 和 \W 字符之间,或者 \w 和字符串开始/结尾的边界

re.findall(r'\bHello\b', 'Hello world! Hello.')
# out: ['Hello', 'Hello']

re.findall(r'\BHello\B', 'Hello worldHello123')
# out: ['Hello']
# Hello 两边都需要 \b 未定义的分隔字符

re.findall(r'\d+', 'ab123d\nabc')
# out: ['123']

re.findall(r'\D+', 'ab123d\nabc')
# out: ['ab', 'd\nabc']

re.findall(r'\s+', 'ab12 3d\nab\tc')
# out: [' ', '\n', '\t']

re.findall(r'\S+', 'ab12 3d\nab\tc')
# out: ['ab12', '3d', 'ab', 'c']

re.findall(r'\w+', 'user_name@host163.com')
# out: ['user_name', 'host163', 'com']

re.findall(r'\W+', 'user_name@host163.com')
# out: ['@', '.']

re.findall(r'dd\Z', 'abddacdd')
re.findall(r'dd$', 'abddacdd')
# out: ['dd']

总结

今天讲了一些扩展标记法,其实没那么难,多看看例子,多练习练习。

下节将介绍 re 模块各函数的用法,敬请期待......

上一篇下一篇

猜你喜欢

热点阅读