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的字符串
- 字符串本身会先进行转义处理
- 正则表达式引擎得到处理之后的字符串后再对字符串进行正则表达式引擎自己的处理
- 开始匹配
# 字符串 # '\\\\' # 经过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] #>>> []