Python学习笔记6

Python学习笔记—6正则表达式

MrZigZag @ Peking University

2015-07-18


1.正则表达式

正则表达式使用一种描述性的语言给字符串定义一个规则,只有符合规则的字符串才能认为是匹配,否则该字符串就是不合法的。

2.精确匹配

如果直接给出字符就是精确匹配。用\d可以匹配一个数字,\w匹配一个字母或者一个数字。.可以匹配任意字符,\s匹配一个空格或者Tab等空白符。

  • 12\d可以匹配123
  • \w\w\w可以匹配www也可以匹配py3
  • py.可以匹配py3pyx等。

3.变长字符匹配

正则表达式中,用*表示任意个字符,用+表示至少一个字符,用?表示0个或者1个字符,用{n}表示n个字符,{n, m}表示n到m个字符。

例如\d{3}\s+\d{3,8}\d{3}表示3个数字,\s表示一个空格,所以\s+表示至少有一个空格,\d{3,8}表示有3-8个数字。因而该正则表达式可以匹配用空格隔开的电话号码。

对于010-62767007之类中间有-的电话号码,因为-是特殊字符,需要转义,可以表示为\d{3}\-\d{3,8}

4.范围匹配

变长字符串无法解决010 - 62767007之类带有空格又带有-的字符串,需要引入[]表示范围。范围的使用示例。

  • [0-9]表示数字,[a-z]表示小写字母。
  • [0-9a-zA-Z\_]表示一个数字、字母或者下划线。
  • [0-9a-zA-Z\_]+表示至少由一个数字、字母或者下划线组成的字符串。
  • [a-zA-Z][0-9a-zA-Z\_]*匹配以字母开头后接任何数字、字母或者下划线的字符串。
  • [a-zA-Z][0-9a-zA-Z]{0, 9}匹配以一个字母开头,后接0-9个数字、字母或者下划线的字符串。

5.特殊符号

A|B表示可以匹配A或者B,[P|p]ython可以匹配Python或者python

^表示行的开头,^\d表示必须以数字开头。

$表示行的结束,\d$表示必须以数字结束。

完全精确匹配可能会匹配比它长的字符串,例如py可以匹配python,要使py只能匹配py,可以加上^$变成整行匹配,表示为^py$

6.使用re模块

Python提供re模块,包含所有正则表达式的功能。因为Python的字符串本身就用\转义,与正则表达式产生冲突,因而一般使用Python的r前缀表示正则表达式,这样就不用考虑转义的问题了。

match()方法判断匹配是否成功,成功返回一个Match对象,否则返回一个None

test_re = r'^\d{3}\-\d{3,8}$`
test_str = '010-62767007`
if re.match(test_re, test_str):
    do something
else:
    do other things

7.切分字符串

用正则表达式切分字符串比用固定的字符更加灵活。

一般的切分无法识别连续的空格。

>>> 'a b   c'.split(' ')
['a', 'b', '', '', 'c']

用正则表达式就可以解决这个问题。

>>> re.split(r'\s+', 'a b   c')
['a', 'b', 'c']
>>> re.split(r'[\s\,]+', 'a b,,,,  c  ')
['a', 'b', 'c']

用正则表达式切分可以将用户输入的不规范的标签转化为正确的数组。

8.分组

除了简单判断字符串是否匹配外,正则表达式还能提取字符串的子串。用()表示要提取的分组,可以直接从目标字符串中提取出需要的子串。

例如要从010-62767007提取出区号和电话号码,可以定义为^(\d{3,4})\-(\d{7,8})$,得到的子串存储为一组group,其中group(0)为源字符串。

>>> m = re.match(r'^(\d{3,4})\-(\d{7,8})$', '010-62767007')
>>> m.group(0)
'010-62767007'
>>> m.group(1)
'010'
>>> m.group(2)
'62767007'

例如给定一个时间,判断是否合法并提取出时分秒。

>>> t_re = r'^(0[0-9]|1[0-9]|2[0-3]|[3-9])\:([0-5][0-9])\:([0-5][0-9])$'
>>> m.re.match(t_re, '19:05:23')
>>> m.group(1)
'19'
>>> m.group(2)
'05'
>>> m.group(3)
'23'

但是这个例子比较难识别日期,因为每个月的天数之间存在差异。

9.贪婪匹配

正则表达式默认使用贪婪匹配,因此会尽量匹配尽可能多的字符,有时候会导致使用+时会出现问题,这时候需要引入非贪婪匹配,一般来说只需在+后面加一个?即可。例如用^(\d+)(0*)$匹配就无法提取出102401后面的01,可以改为^(\d+?)(0*)$

10.编译

使用正则表达式时,Python解释器内部会先编译正则表达式然后用编译好的表达式去匹配字符串。如果一个正则表达式要使用多次,可以先执行编译,接下来重复使用就不用编译了。

>>> re_time = re.compile(r'^(0[0-9]|1[0-9]|2[0-3]|[3-9])\:([0-5][0-9])\:([0-5][0-9])$')
>>> re_time.match('20:14:59').group(3)
'59'