原文地址:python正则表达式转义注意事项
无论哪种语言,在使用正则表达式的时候都避免不了一个问题,就是在匹配元字符的时候,需要对元字符进行转义,让
正则表达式引擎将其当做普通字符来匹配。本文主要以python为例,说明一下转义中需要注意的问题。
python的正则表达式中需要转义的元字符有以下几个:
python中对元字符的转义使用双反斜杠 \\ 来表示
# 普通元字符的转义
_string = '''
!@#$%^&
'''
# 不转义
print re.findall('$', _string)
#>>> ['', '']
# 双反斜杠转义
print re.findall('\\$', _string)
#>>> ['$']
# 单反斜杠转义
print re.findall('\$', _string)
#>>> ['$']
看上面的例子大家可能会发现,使用一个反斜杠 \ 也可以达到转义的效果,那为什么还要写两个呢?这得先搞清楚python的字符串转义(不是正则表达式转义),python本身使用 \ 来转义一些特殊字符,比如在字符串中加入引号的时候,为了
s = 'i\'m superman'
print s
#>>> i'm superman
防止和字符串本身的引号冲突,使用 \ 来转义,一般情况下这个也不会引起什么问题,但是当你要使用 \ 来转义 \ 的时候,就比较混乱了,比如我们想要输出一个 \ ,得写两个 \ ,否则会报语法错误,因为 \ 把后面的引号给转义了,必须使用 \
# 错误写法
# print '\'
# 正确写法
print '\\'
#>>> \
# 原生字符串
print r'\\'
#>>> \\
将 \ 转义一下使其不具备转义功能,才可以正确输出,当使用原生字符串的时候,输出显示了两个 \ ,看起来好像是写几个输出几个的样子,如果这样想的话,你可以试一下,看能不能输出奇数个 \。
先来说一下什么是原生字符串,其实就是不进行特殊处理的字符串,所谓特殊处理,貌似就是针对转义的,原生字符串的诞生本身就是为了解决转义的时候写了太多 \ 的问题,但是为什么使用了原生字符串仍然不能只输出一个 \ 呢?其实这应该算是一个bug,就是python的字符串不能以奇数个 \ 结尾,这样的写法会被认为是将结尾的引号进行了转义,导致语法错误。具体可以参考http://t.cn/RfolM3H。
虽然原生字符串并不是很完美,但它已经可以帮我们解决很大一部分问题了。比如当你想匹配 \ 的时候,原生字符串可
_string = '\\\\'
print _string
#>>> \\
# 字符串
for i in re.findall('\\\\', _string):
print i
#>>> \
#>>> \
# 原生字符串
for i in re.findall(r'\\', _string):
print i
#>>> \
#>>> \
以让你少写一半的 \ ,既节省代码量,又增加可读性。
说了这么多也没说为什么在写正则表达式的时候一个 \ 也可以起到转义的作用。我们先来分析一下一个字符串被正则表
达式引擎解析的过程,一共有4步:
# 字符串
# '\\\\'
# 经过python处理之后
# '\\'
# 正则表达式引擎接收到的
# '\\'
# 正则表达式引擎进行转义处理后 可以匹配到 \
# '\'
而当使用原生字符串的时候就变为了3步:
# 原生
# '\\'
# 不再处理
# '\\'
# 正则表达式引擎接收到的
# '\\'
# 正则表达式引擎进行转义处理
# '\'
下面是最重要的一个,当使用一个 \ 转义的时候,python会识别不了转义序列,于是它就不做任何处理,直接传给了正则表达式引擎。这就解释了为什么一个 \也可以转义。这个不算bug,虽然方便了使用,但会让人很迷惑,有利有弊吧。
# 原生
# '\$'
# 识别不了 不进行处理
# '\$'
# 正则表达式引擎接收到的
# '\$'
# 正则表达式引擎进行转义处理
# '$'
下面举几个例子看一下:
# 匹配 \d+
_string = 'i am \d+'
print re.findall('\\\\d\\+', _string)[0]
#>>> \d+
print re.findall(r'\\d\+', _string)[0]
#>>> \d+
# 匹配 []
_string = 'i am []'
print re.findall('\\[\\]', _string)[0]
#>>> []
print re.findall('\[\]', _string)[0]
#>>> []
print re.findall(r'\[\]', _string)[0]
#>>> []