正则表达式——元字符与转义

1.4  元字符与转义

在上面的例子里,字符组中的横线-并不能匹配横线字符,而是用来表示范围,这类字符叫做元字符(meta-character)。字符组的开方括号[、闭方括号]和之前出现的^、$都算元字符。在匹配中,它们有着特殊的意义。但是,有时候并不需要表示这些特殊意义,只需要表示普通字符(比如"我就想表示横线字符-"),此时就必须做特殊处理。

先来看字符组中的-,如果它紧邻着字符组中的开方括号[,那么它就是普通字符,其他情况下都是元字符;而对于其他元字符,取消特殊含义的做法都是转义,也就是在正则表达式中的元字符之前加上反斜线字符\。

如果要在字符组内部使用横线-,最好的办法是将它排列在字符组的最开头。[-09]就是包含三个字符-、0、9的字符组;[0-9]是包含0~9这10个字符的字符组,[-0-9]则是由"-范围表示法"0-9和横线-共同组成的字符组,它可以匹配11个字符,例1-9说明了使用横线-的各种情况。

例1-9  -出现在不同位置,含义不同

#作为普通字符  
re.search("^[-09]$", "3") != None       #  => False  
re.search("^[-09]$", "-") != None       #  => True  
#作为元字符  
re.search("^[0-9]$", "3") != None       #  => True  
re.search("^[0-9]$", "-") != None       #  => False  
#转义之后作为普通字符  
re.search("^[0\\-9]$", "3") != None     #  => False  
re.search("^[0\\-9]$", "-") != None     #  => True  

仔细观察会发现,在正文里说"在正则表达式中的元字符之前加上反斜线字符\",而在代码里写的却不是[0\-9],而是[0\\-9]。这并不是输入错误。

因为在这段程序里,正则表达式是以字符串(String)的方式 提供的,而字符串本身也有关于转义的规定(你或许记得,在字符串中有\n、\t之类的转义序列)。上面说的"正则表达式",其实是经过"字符串转义处理"之后的字符串的值,正则表达式[0\-9]包含6个字符:[、0、\、-、9、],在字符串中表达这6个字符;但是在源代码里,必须使用7个字符: \需要转义成\\,因为处理字符串时,反斜线和之后的字符会被认为是转义序列(Escape Sequence),比如\n、\t都是合法的转义序列,然而\-不是。

这个问题确实有点麻烦。正则表达式是用来处理字符串的,但它又不完全等于字符串,正则表达式中的每个反斜线字符\,在字符串中(也就是正则表达式之外)还必须转义为\\。所以之前所说的是"正则表达式[0\-9]",程序里写的却是[0\\-9],这确实有点麻烦。

不过,Python提供了原生字符串(Raw String),它非常适合于正则表达式:正则表达式是怎样,原生字符串就是怎样,完全不需要考虑正则表达式之外的转义(只有双引号字符是例外,原生字符串内的双引号字符必须转义写成\")。原生字符串的形式是r"string",也就是在普通字符串之前添加r,示例代码如例1-10。

例1-10  原生字符串的使用

#原生字符串和字符串的等价  
r"^[0\-9]$" == "^[0\\-9]$"              #  => True  

#原生字符串的转义要简单许多 re.search(r"^[0\-9]$", "3") != None # => False re.search(r"^[0\-9]$", "-") != None # => True

原生字符串清晰易懂,省去了烦琐的转义,所以从现在开始,本书中的Python示范代码都会使用原生字符串来表示正则表达式。另外,.NET和Ruby中也有原生字符串,也有一些语言并没有提供原生字符串(比如Java),所以在第6章(?93)会专门讲解转义问题。不过,现在只需要知道Python示范代码中使用了原生字符串即可。

继续看转义,如果希望在字符组中列出闭方括号 ],比如[012]345],就必须在它之前使用反斜线转义,写成[012\]345];否则,结果就如例1-11所示,正则表达式将]与最近的[匹配,这个表达式就成了"字符组[012]加上4个字符345]",它能匹配的是字符串0345]或1345]或2345],却不能匹配 ]

例1-11  ]出现在不同位置,含义不同

#未转义的]  
re.search(r"^[012]345]$", "2345") != None       #  => True  
re.search(r"^[012]345]$", "5") != None          #  => False  
re.search(r"^[012]345]$", "]") != None          #  => False  
#转义的]  
re.search(r"^[012\]345]$", "2345") != None      #  => False  
re.search(r"^[012\]345]$", "5") != None         #  => True  
re.search(r"^[012\]345]$", "]") != None         #  => True  

 

 

posted @ 2018-10-19 10:22  gaara724  阅读(1131)  评论(0编辑  收藏  举报