Python 正则表达式-语义化正则

Python 正则表达式

python的正则表达式是在re模块,属于内置模块。正则表达式格式的详细说明见文章结束表, 模式的构建通过pattern= re.compile(regex_str, flag)构建,下面是python正则常用的函数。

python 正则函数 函数用法说明
p= re.compile(regex_str, flag) 正则模式构建
m = p.match(target_str) str是否符合某种模式,从str开始位置进行扫描
m = p.search(target_str) str是否包含某种模式的字符串,扫描整个字符串

上面返回的结果是一个match对象(匹配的结果放在其成员regs中,没有匹配特征m为空对象None),返回的结果可以通过m.group(idx)、m.groups()、m.groupdict()获取,从名字我们可以得知这是取分组的函数:

正则匹配结果 函数用法说明
m.group(idx=0) 整个正则字符串属于一个最大的分组,匹配的字符串默认放在下标为0的位置,整个字符串匹配的结果通过m.group()
正则表达式中()表示一个分组,正则字符串中的()匹配的结果通过m.group(idx)获取
m.groups() 取正则字符串中括号分组匹配的所有结果,返回一个元组
m.groupdict() 该功能需要与python独有的正则匹配规则配合使用

(1) match、search的区别:

>>> import re
>>> target_str = "Tom Cat"
>>> target_str2 = "***Tom--Tom Cat"
>>> p = re.compile(r"\w+ \w+")
# \w表示代码变量字符(字母数字下划线), + 表示匹配次数(1次或多次)
>>> m1 = p.match(target_str)
>>> s1 = p.search(target_str2)
>>>m1.group()
'Tom Cat'
>>>s1.group()
'Tom Cat'
>>>m1.groups()
()

(2) group()、groups()取分组值:

>>> import re
>>> target_str = "Tom Cat"
>>> p2 = re.compile(r"(\w+) (\w+)")
>>> m2 = p2.match(target_str)
>>> m2.group()
'Tom Cat'
>>> m2.group(1)
'Tom'
>>> m2.group(2)
'Cat'
>>> m2.groups()
('Tom', 'Cat')
>>> m2.gruopdict()
{}

(3) groupdicit()的使用:

先直接看一个例子,使得上面的正则匹配规则更有语义:

>>> import re
>>> target_str = "Tom Cat"
>>> p3 = re.compile(r"(?P<name>\w+) (?P<animal>\w+)")
>>> m3 = p3.match(target_str)
>>> m3.group()
'Tom Cat'
>>> m3.group('name')
'Tom'
>>> m3.group('animal')
'Cat'
>>> m2.groups()
('Tom', 'Cat')
>>> m2.gruopdict()
{'name': 'Tom', 'animal': 'Cat'}

python更有语义化的正则模式的构建(?P),下表中…代表正则模式字符串:

分组正则模式 功能说明
(…) 匹配括号内的任何正则表达式,并指示组的开始和结束。
要匹配括号本身(、),请使用\(或\),或将它们括在字符类内:[(],[)]。
(?P…) 与普通括号类似,表示一个组;但通过组匹配的子字符串可以通过符号组名访问,注意:
组名必须是有效的Python标识符,并且每个组名只能在正则表达式中定义一次。
(?: …) 普通括号的非捕获版本,匹配括号内的任何正则表达式,可以匹配0个或者多个
re.VERBOSE 忽略换行,这个标志允许您通过可视化地分离模式的逻辑部分并添加注释,
来编写外观更好、可读性更好的正则表达式,非常适合和上述的正则模式搭配,是re.compile()的flag参数

一个werkzug路由的匹配实例:

_rule_re = re.compile(
    r"""
    (?P<static>[^<]*)                           # static rule data		(1)  # (a)
    < 	
    (?:																         # (b)																		
        (?P<converter>[a-zA-Z_][a-zA-Z0-9_]*)   # converter name	    (2)
        (?:\((?P<args>.*?)\))?                  # converter arguments	(3)
        \:                                      # variable delimiter	(4)
    )?
    (?P<variable>[a-zA-Z_][a-zA-Z0-9_]*)        # variable name			(5)	 # (c)
    >
    """,
    re.VERBOSE,
)

我们可以先来看一个完全匹配上面正则的实例:/doc/<string(length=2):lang_code>,实际的字符串“/doc/cn”、“/doc/en”都可以与之相匹配;上面的正则表达式总体由(a)(b)(c)三个带括号的部分组成:

注意: 所有编程语言,函数后变量都只能由数字字母下划线组成,并且不能以数字开头 (d)

组成部分 说明
(a) 匹配所有非<字符,即遇到<该部分匹配完成
(b) 整体(?:)结构,表示这部分可以不出现(0/n次)
(2) 匹配类型转换名称,有效的python函数名
(3) 匹配 类型转换的参数,这一部分可以不出现,有则通过()匹配始末
(4) 类型转换 后面必须跟冒号
© 匹配有效的变量名(符合d)

以上正则的匹配实例:路由会根据正则的形式,生成符合对应路径的正则表达式,用来匹配请求路径

# (1) 不匹配正则,直接路径判等
"/"
"/doc1"
# (2) (b)的类型转换不出现
"/doc2/<lang_code>"
# (3) (b)(3) 类型转换的参数不出现
"/doc3/<int:lang_code>"
# (4) 所有结构全出现
"/doc4/<string(length=2):lang_code>"
上一篇:单例设计模式


下一篇:常用linux查询日志内容命令