问题
你正在试着用正则表达式去匹配一大块的文本,而你需要跨越多行去匹配。
解决方案
这个问题很典型的小淮娘在当你用点(.)去匹配任意字符的时候,忘记了点(.) 不能匹配换行符的事实。比如假设你想试着匹配C语言分割的注释:
import re
comment = re.compile(r'/\*(.*?)\*/')
text1 = '/* this is a comment */'
text2 = '''/* this is a
'comment */
'''
print(comment.findall(text1)) # ->[' this is a comment ']
print(comment.findall(text2)) # -> []
为了修正 这个问题,可以修改模式字符串,增加对换行的支持,比如
comment = re.compile(r'/\*((?:.|\n)*?)\*/')
print(comment.findall(text1)) # ->[' this is a comment ']
print(comment.findall(text2)) # -> [" this is a \n 'comment "]
在这个模式中,(?:.|\n)指定了一个非捕获组(有就是它定义了一个仅仅用来做匹配,而不能通过简单捕获或者编码的组)。
讨论
re.compile()函数接受一个标志参数叫re.DOTALL,在这里非常有用,它可以让正则表达式的点(.)匹配包括换行符在内的任意字符。比如:
comment=re.compile(r'/\*(.*?)\*/',re.DOTALL)
print(comment.findall(text2)) # ->[" this is a \n 'comment "]
标记参数工作的很好,但是如果模式非常复杂或者是为了构造字符串令牌而将多个模式合并起来,这时候使用这个标记参数就可能出现一些问题。如果让你选择的话,最好还是自定义的正则表达模式,这样可以在不需要额外的标记参数下也能工作的很好。