匹配模式
贪婪模式
实际需求是尽可能短的匹配需要的结果,但在使用正则表达式字符串匹配某个文本时,它找到的是符合模式的却是最长可能的匹配。
产生这样的原因,是因为 *
、+
和 ?
限定符都是贪婪的,它们会尽可能的匹配符合模式的文字,举例说明:
>>> import re
>>> text1 = '<h1>'
>>> pattern = re.compile(r'<.*>')
>>> re.findall(pattern, text1)
['<h1>']
>>> text2 = '<h1>Introduction to Regular Expressions</h1>'
>>> re.findall(pattern, text2)
['<h1>Introduction to Regular Expressions</h1>']
在上面的例子中,模式 r'<.*>'
意图是匹配被单书名号包含的内容。但是上面提及的 *
限定符是贪婪的,因此匹配操作会尽可能长的匹配结果。所以,第二个搜索 text2
的结果并不是实际需求的结果。
非贪婪模式(最小匹配模式)
解决限定符贪婪,尽可能多匹配的情况,只要在限定符(比如 *
,+
,?
)后面加上问号 ?
修饰符,就可以让模式变为非贪婪模式,从而实现非贪婪或最小匹配,延用上面的例子:
>>> pattern = re.compile(r'<.*?>') # 这里在 * 限定符后面添加 ? 修饰符
>>> text2 = '<h1>Introduction to Regular Expressions</h1>'
>>> re.findall(pattern, text2)
['<h1>', '</h1>']
现在示例最终得到的结果,['<h1>', '</h1>']
,就是实际需求的结果 。
多行匹配模式
实际操作文本匹配时,并非如示例简单提供的只有单行的内容。有时,使用正则表达式匹配文本时,往往需要跨多行去匹配,从而得到实际需要的结果。
元字符 .
,能够匹配除换行符以外的任意字符,但实际使用中,往往会忽略这一点。例如匹配 C
语言分割的注释:
>>> import re
>>> pattern = re.compile(r'/\*(.*?)\*/')
>>> text1 = '/* this is a comment */'
>>> text2 = '''/* this is a
... multiline comment */
... '''
>>> re.findall(pattern, text1)
[' this is a comment ']
>>> re.findall(pattern, text2)
[]
这里有一种方法是修改模式字符串,增加对换行的支持。示例如下:
>>> import re
>>> pattern = re.compile(r'/\*((?:.|\n)*?)\*/')
>>> text2 = '''/* this is a
... multiline comment */
... '''
>>> re.findall(pattern, text2)
[' this is a\n multiline comment ']
修改的模式中,(?:...)
表示是非捕获分组(即使仅仅用作匹配,并不能通过单独捕获或者编号的组)。
re.DOTALL
re
模块还提供一个标记参数 re.DOTALL
。上面示例已经提及,元字符 .
并不能够匹配换行符,而增加这个标记参数后,.
能够匹配任何字符, 包括换行符。示例如下:
>>> import re
>>> pattern = re.compile(r'/\*(.*?)\*/', re.DOTALL)
>>> text2 = '''/* this is a
... multiline comment */
... '''
>>> re.findall(pattern, text2)
[' this is a\n multiline comment ']
re.DOTALL
只是 re
模块提供的其中一个标记参数。需要了解更详细的内容,可查阅官方文档:
https://docs.python.org/zh-cn/3.6/library/re.html
参考资料
书籍
- David M. Beazley;Brian K. Jones.Python Cookbook, 3rd Edtioni.O’Reilly Media.2013.ISBN 9781449340377
以上就是本篇的主要内容。