目录
首发于:
最近更新于:
分类: posts

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)

然后默认 . 是不会匹配换行符号的,如果要引入换行符则要如上所示加上。