文章目录1 问题
- 1 问题
- 2. 解决方案
- 3. 讨论
你希望使用正则表达式匹配文本中的多行字符串。
2. 解决方案针对这个问题,很多人第一反应是通过 . 符号匹配任意字符的方式来解决,但很多人忘了在正则表达式中,直接使用符号 . 并不能匹配换行符。例如,假定你希望尝试匹配 C 语言形式的注释:
>>> text1 = '' >>> text2 = ''' ... ''' >>> re.findall(r'/*(.*?)*/', text1) [' this is a comment '] >>> re.findall(r'/*(.*?)*/', text2) [] >>> comment_pattern = re.compile(r'/*(.*?)*/') >>> comment_pattern.findall(text1) [' this is a comment '] >>> comment_pattern.findall(text2) []
对于上述示例,需要说明的两点是:
- 对于 findall() 函数,其返回值是一个列表,列表中每个元素都是第一个参数即正则表达式匹配的结果,且当正则表达式中存在分组时,列表的每个元素只包含分组中的内容,且当有多个分组的时候,列表的每个元素是元组形式给出的分组匹配内容;
- 对于正则表达式 '/*(.*?)*/' ,之所以要在分组中加上 ? ,是为了避免在待匹配文本中存在多个 形式的字符串时,仅匹配出第一个 之间的内容,具体请见【Python 每日一技】使得正则表达式匹配最短的字符串。
为了解决上述问题,你可以稍微修改一下正则表达式的形式,以让其支持对于换行符的匹配:
>>> re.search(r'/*((?:.|n)*?)*/', text2)>>> re.search(r'/*((?:.|n)*?)*/', text2).group(0) '' >>> re.search(r'/*((?:.|n)*?)*/', text2).group(1) ' this is an multiline comment ' >>> re.findall(r'/*((?:.|n)*?)*/', text2) [' this is an multiline comment '] >>> comment_pattern = re.compile(r'/*((?:.|n)*?)*/') >>> comment_pattern.findall(text2) [' this is an multiline comment ']
在上述解决方案中,(?:.|n) 部分表示指定一个非捕捉式分组,即该分组存在的唯一目的只是用匹配,但是该分组并不会被编号后使用。
3. 讨论实际上,函数 re.compile() 还支持一个键值对参数 flags ,在将该参数指定为 re.DOTALL 时就可以让 . 也能匹配回车换行符了。例如:
>>> re.search(r'/*(.*?)*/', text2, flags=re.DOTALL)>>> re.search(r'/*(.*?)*/', text2, flags=re.DOTALL).group(0) '' >>> re.search(r'/*(.*?)*/', text2, flags=re.DOTALL).group(1) ' this is an multiline comment ' >>> re.findall(r'/*(.*?)*/', text2, flags=re.DOTALL) [' this is an multiline comment '] >>> comment_pattern = re.compile(r'/*(.*?)*/', flags=re.DOTALL) >>> comment_pattern.findall(text2) [' this is an multiline comment ']



