Image

在编写处理字符串的程序或网页时,经常会有查找符合某些复杂规则的字符串的需要
正则表达式就是用于描述这些规则的工具。换句话说,正则表达式就是记录文本规则的代码。

正则表达式并不是python中特有的功能,它是一种通用的方法。python中的正则表达式库,所做的事情是利用正则表达式来搜索文本。要使用它,你必须会自己用正则表达式来描述文本规则。

#1. 入门
有个正则表达式是hi,那么它就可以匹配出文本中所有含有hi的字符

Hi, I am Shirley Hilton. I am his wife.

完全匹配后,会得到两个hi, 两个hi分别来自Shirleyhis

1
2
3
4
5
6
7
8
9
10
#字符串前面加了r,是raw的意思,它表示对字符串不进行转义, 不理会任何转义字符串,如"\n"等
import re
text = "Hi, I am Shirley Hilton. I am his wife."
m = re.findall(r"hi", text)
if m :
print m
else :
print "No match"
#如果只想找到 hi 这个单词,而不把包含它的单词也算在内,那就可以使用“\bhi\b”这个正则表达式

##1.1. 元字符

  • \b在正则表达式中表示单词的开头或结尾,空格、标点、换行都算是单词的分割。而\b自身又不会匹配任何字符,它代表的只是一个位置

对与上面的代码正则表达式修改为’\bhi\b’, 则输出结果为No match

  • .表示匹配除了换行符以外的任意字符

对于上述代码中的正则修改为i., 输出结果为[‘i,’, ‘ir’, ‘il’, ‘is’, ‘if’]

  • .类似的一个符号是“\S”,它表示的是不是空白符的任意字符, 这里S是大写

对于上面代码正则表达式修改为i\S,则输出结果为[‘i,’, ‘il’, ‘il’, ‘is’, ‘if’]

  • 在很多搜索中,会用?表示任意一个字符,*表示任意数量连续字符,这种被称为通配符. 但在正则表达式中,任意字符是用.表示,而*则不是表示字符,而是表示数量:它表示前面的字符可以重复任意多次(包括0次),只要满足这样的条件,都会被表达式匹配上。()
    \bhi\b.*\bLucy\b的意思:先是一个单词hi,然后是任意个任意字符(但不能是换行),最后是Lucy这个单词
1
2
3
4
5
6
7
8
9
10
11
12
re.findall(r"I.*e", text)最终匹配结果为:
['I am Shirley Hilton. I am his wife']
#“*”在匹配时,会匹配尽可能长的结果
#想让他匹配到最短的就停止,需要用“.*?”
m = re.findall(r"I.*?e", text)
匹配结果为['I am Shirle', 'I am his wife'] #懒惰匹配
//匹配 "site sea sue sweet see case sse ssee loses"中所有以s开头以e结尾的单词
text1= "site sea sue sweet see case sse ssee loses"
m = re.findall(r"\bs\S*e\b", text1)// 意思是匹配以s开头的任意字符串(但不是空白符),最后以e结尾的字符串
//打印结果['site', 'sue', 'see', 'sse', 'ssee']
  • \d匹配一位数字(0,或1,或2,或……)

0\d{2}-\d{8}。这里\d后面的{2}({8})的意思是前面\d必须连续重复匹配2次(8次)

  • \s匹配任意的空白符,包括空格,制表符(Tab),换行符,中文全角空格, 这里s是小写

对于第一段代码正则表达式修改为I\s,则输出结果为[‘I ‘, ‘I ‘]

  • \w匹配字母或数字或下划线或汉字等
1
2
3
4
5
6
7
8
9
//一些例子
1. \ba\w*\b匹配以字母a开头的单词——先是某个单词开始处(\b),然后是字母a,然后是任意数量的字母或数字(\w*),最后是单词结束处(\b)
2. \d+匹配1个或更多连续的数字。这里的+是和*类似的元字符,不同的是*匹配重复任意次(可能是0次),而+则匹配重复1次或更多次
3. \b\w{6}\b 匹配刚好6个字符的单词
4. ^\d{5,12}$ 匹配5到12个数字, ^表示数字的开始, $表示数字的结束
代码 说明
. 匹配除换行符以外的任意字符
\w 匹配字母或数字或下划线或汉字
\s 匹配任意的空白符
\d 匹配数字
\b 匹配单词的开始或结束
^ 匹配字符串的开始
$ 匹配字符串的结束

##1.2. 重复

代码/语法 说明
* 重复零次或更多次
+ 重复一次或更多次
? 重复零次或一次
{n} 重复n次
{n,} 重复n次或更多次
{n,m} 重复n到m次
  1. Windows\d+匹配Windows后面跟1个或更多数字
  2. ^\w+匹配一行的第一个单词

##1.3. 字符类

  • []表示满足括号中任一字符。比如[hi],它就不是匹配hi了,而是匹配h或者i

对于上面代码正则表达式修改为[hi],则输出结果为[‘i’, ‘h’, ‘i’, ‘i’, ‘h’, ‘i’, ‘i’]

[aeiou]就匹配任何一个英文元音字

[.?!]匹配标点符号(.或?或!)

[0-9]代表的含意与\d就是完全一致的:一位数字

[a-z0-9A-Z_]也完全等同于\w

##1.4. 反义

代码/语法 说明
\W 匹配任意不是字母,数字,下划线,汉字的字符
\S 匹配任意不是空白符的字符
\D 匹配任意非数字的字符
\B 匹配不是单词开头或结束的位置
[^x] 匹配除了x以外的任意字符
[^aeiou] 匹配除了aeiou这几个字母以外的任意字符
  1. \S+匹配不包含空白符的字符串。
  2. <a[^>]+>匹配用尖括号括起来的以a开头(除了>以外)的字符串。

##1.5. 分枝条件
写出一个正则表达式用于匹配下面的数字串
(021)88776543
010-55667890
02584453362
0571 66345673
很容易写出\(?0\d{2, 3}[) -]?\d{8}, \(?表示出现0个或者1个做括号, \d{2, 3}表示匹配2个或者3个数字, [) -]?表示匹配)或者-或者空格, \d{8}表示匹配8个数字
但是这样依然不能正确的表示以上的数字串, 可能出现括号不匹配的问题, 例如(02188776543也会匹配成功

这里需要使用|类似与数学中或操作

可以写出\(0\d{2,3}\)\d{7,8}|0\d{2,3}[ -]?\d{7,8}, 其中(是对括号进行转义, ()在正则表达式中有特定的用途,另外|操作匹配时,会按照从左往右的顺序,一旦匹配成功就停止验证后面的规则

#2.Python中的re模块

##2.1. 模块函数

1
2
3
4
5
6
7
#引入re模块
import re
#将一个正则表达式的样式转化为Python中正则表达式对象
re.compile(pattern, flags=0)
#范例, pattern为正则表达式, 在Python中使用正则表达式要在前面加r
b = re.compile(r"\d+\.\d*")
1
2
3
4
5
6
#在string中扫描, 找到正则表达式第一个匹配的位置, 返回MatchObject实例, 没有匹配到会返回None, 我们可以使用group(num) 或 groups() 匹配对象函数来获取匹配表达式。
re.search(pattern, string, flags=0)
m = re.search("output_(\d{4})", "output_1986.txt")
print(m.group(1))
1
2
3
4
5
6
7
8
9
10
11
12
#如果有0和或者多个串从头开始和pattern正则表达式匹配,返回MatchObject实例, 没有匹配到返回None, 我们可以使用group(num) 或 groups() 匹配对象函数来获取匹配表达式。
re.match(pattern, string, flags=0)
text = "Hi, I am Shirley Hilton. I am his wife."
m = re.match(r"H\w", text)//此时会匹配成功返回MatchObject
if m :
print m.group(0)
else :
print "No match"
#输出Hi
m = re.match(r"i\w", text)//此时会匹配失败返回None

re.match与re.search的区别
re.match只匹配字符串的开始,如果字符串开始不符合正则表达式,则匹配失败,函数返回None;而re.search匹配整个字符串,直到找到一个匹配。

1
2
3
4
5
6
7
8
9
10
11
#根据正则表达式分割字符串, 将分割后的所有子字符串放在一个表(list)中返回
re.split(pattern, string, maxsplit=0, flags=0)
text = "Hi, I am Shirley Hilton. I am his wife."
m = re.split(r"[Ii]", text)#以I或者i对text进行划分
if m :
print m
else :
print "No match"
#输出结果['H', ', ', ' am Sh', 'rley H', 'lton. ', ' am h', 's w', 'fe.']
1
2
#根据正则表达式搜索字符串,将所有符合的子字符串放在一给表(list)中返回
re.findall(pattern, string, flags=0)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#用于替换字符串中的匹配项,如果模式没有发现,字符将被没有改变地返回
re.sub(pattern, repl, string, max=0)
import re
phone = "2004-959-559 # This is Phone Number"
num = re.sub(r'#.*$', "", phone) #删除Python中#的注释
print num
# Remove anything other than digits
num = re.sub(r'\D', "", phone)
print num
#输出结果为
2004-959-559
2004959559

#3. 参考链接

正则表达式30分钟入门教程
Python正则表达式操作指南
Python官方文档