re模块
re模块提供了python对于正则表达式的支持,对于字符串操作,如果之前在介绍字符串类型的一些方法(比如split,replace等等),能够用它们解决问题就用它们,因为更快更简单。实在需要动用正则表达式理念才考虑使用re模块,而且你要克制写很多或者很复杂的(除非某些特殊情况)正则表达式的冲动,因为正则表达式的引入将会使得整个程序都更加难懂和不可捉摸。
更多内容请参见官方文档。
re模块中的元字符集
.
-
表示一行内的任意字符,如果如果通过re.compile指定re.DOTALL,则表示多行内的任意字符,即包括了换行符。此外还可以通过字符串模板在它的前面加上(?s)来获得同样的效果。
*
-
对之前的字符匹配或者多次。
+
-
对之前的字符匹配或者多次。
?
-
对之前的字符匹配或者。
{m}
-
对之前的字符匹配()m次。
{m,n}
-
对之前的字符匹配m次到n次,其中n次可能省略,视作默认值是无穷大。
^
-
表示字符串的开始,如果加上re.MULTILINE选项,则表示行首。此外字符串模板加上(?m)可以获得同样的效果。
$
-
表示字符串的结束,同
^
类似,如果加上re.MULTILINE选项,则表示行尾,可以简单理解为\n
换行符。此外字符串模板加上(?m)可以获得同样的效果。$
符号在re.sub函数中可以被替换为另外一个字符串,其具体效果就是原字符串尾加上了这个字符串,类似的^
被替换成某个字符串,其具体效果就是原字符串头加上了这个字符串。这里显然^
和$
在字符串中都不是真实存在的字符,而没有这个所谓的标记,所以这种替换总给人怪怪的感觉。 []
-
$$abc$$字符组匹配一个字符,这个字符是a或者b或者c。类似的$$a-z$$匹配所有的小写字母,
[\w]
匹配任意的字母或数字,具体请看下面的特殊字符类。 |
-
相当于正则表达式内的匹配或逻辑。
()
-
圆括号包围的部分将会记忆起来,方便后面调用。这个后面在谈及。
re模块中的特殊字符类
\w 任意的字母或数字 [a-zA-Z0-9_] (meaning word)
\W 匹配任何非字母非数字 [^a-zA-Z0-9_]
\d [0-9] (digit) 数字
\D [^0-9] 非数字
\s 匹配任何空白字符 [ \t\n\r\f\v] 。
\S 匹配任何非空白字符
匹配中文:[\u4e00-\u9fa5]
\b 文档说严格的定义是\w 和\W 之间的边界,反之亦然。粗略的理解可以看作是英文单词头或者尾。
其中^
在方括号[]里面,只有在最前面,才表示排除型字符组的意思。
转义问题
正则表达式的转义问题有时会比较纠结。一个简单的原则是以上谈及的有特殊作用的字符有转义问题,如果python中的字符都写成r''
这种形式,也就是所谓的raw string形式,这样\n
在里面就可以直接写成\n
,而\section
可以简单写为\\section
即可,也就是\
字符需要转义一次。
然后字符组的方括号内[]有些字符有时是不需要转义的,这个实在不确定就转义吧,要不就用正则表达式工具测试一下。
re模块的使用
compile方法生成regular expression object这一条线这里略过了,接下来的讨论全部基于(原始的)字符串模板。
字符串模板前面提及(?m)
和(?s)
的用法了,然后**(?i)**
表示忽略大小写。
匹配和查找
search,match方法简单地用法就是:
re.search(字符串模板, 待匹配字符串)
re.match(pattern, string)
它们将会返回一个match object或者none,其中match object在逻辑上就是真值的意思。match对字符串的匹配是必须从一开始就精确匹配,这对于正则表达式多少0有点突兀。推荐使用search方法,如果一定要限定行首,或者字符串开始可以用前面讨论的正则表达式各个符号来表达。请看下面的例子。
import re
string = '''this is test line.
this is the second line.
today is sunday.'''
match = re.search('(?m)^today',string)
if match:
print('所使用的正则表达式是:',match.re)
print('所输入的字符串是:',match.string)
print('匹配的结果是:',match.group(0))
print('匹配的字符串index',match.span())
else:
print('return the none value')
前面说道圆括号的部分将会记忆起来,作为匹配的结果,默认整个正则表达式所匹配的全部是group中的第0个元素,然后从左到右,子group编号依次是1,2,3......。
所使用的正则表达式是: re.compile('(?m)^today', re.MULTILINE)
所输入的字符串是: this is test line.
this is the second line.
today is sunday.
匹配的结果是: today
匹配的字符串index (44, 49)
具体这些信息是为了说明情况,实际最简单的情况可能就需要判断一下是不是真值,字符串模板是不是匹配到了即可。
分割操作
re模块的split函数可以看作字符串的split方法的升级版本,对于所描述的任何正则表达式,匹配成功之后都将成为一个分隔符,从而将原输入字符串分割开来。
请参看下面的例子并理解其做了什么工作。
import re
def zwc(string):
#中英文常用标点符号
lst = re.split('([\u4e00-\u9fa5\s,。;])',string)
#去除 空白
#去除\s 中英文常用标点符号
lst = [i for i in lst if not i in
[""," ","\n","\t","\r","\f","\v",";",",","。"]]
print(lst)
if __name__ == '__main__':
string='''道可道,非常道。名可名,非常名。無名天地之始,有名萬物之母。
故常無欲,以觀其妙;常有欲,以觀其徼。此兩者同出而異名,
同謂之玄,玄之又玄,眾妙之門。 '''
zwc(string)
替换操作
基于正则表达式的替换操作非常的有用,其实前面的search方法,再加上具体匹配字符串的索引值,然后修改原字符串,然后再search这样循环操作下去,就是一个替换操作了。re模块有sub方法来专门解决这个问题。
非最长匹配
本小节参考了 python cookbook 的 2.7 小节,比如说:
re.compile(r'"(.*)"')
这将匹配两个双引号之间的内容,其默认是最长匹配,也就是多个双引号组成的句子都会匹配进去,你可以如下要要求最短匹配:
re.compile(r'"(.*?)"')
非捕获组
看下面的正则表达式, (?:...)
这个括号的组是非捕获组,也就是不会进入
.group 里面去。
re.search(r'((?:.|\n)*)',text2)
然后默认 .
是不会匹配换行符号的,如果要引入换行符则要如上所示加上。