Table of Contents
re模块
python通过re模块来实现正则表达式与字符串的匹配。
re的match函数需要两个参数,参数一正则表达式、参数二被匹配的字符串。
如下:
>>> re.match('\d','12345') # 匹配成功返回match对象,同时返回匹配到的字符
<re.Match object; span=(0, 1), match='1'> # \d 代表匹配一个数字,匹配字符串的第一个字符
>>> re.match('\d','a12345') # 匹配不成功返回None
match函数执行过程当中,分为两步:
1、编译正则表达式
2、与字符串匹配
所以如果一个正则表达式会被多次使用,我们可以预先编译好正则表达式,需要匹配的时候直接对比就好,就无需每次都调用match函数进行编译的重复操作了。
预先编译的方式如下:
>>> match_number = re.compile('\d') # 预先编译好
>>> match_number.match('123') # 匹配时这么调用
<re.Match object; span=(0, 1), match='1'>
>>> match_number.match('123') # 再次调用也不会再次编译
<re.Match object; span=(0, 1), match='1'>
还要注意一点,因为正则表达式很多字符匹配都是 以 \ 开头的,但是在python中 \ 代表转义字符,且python会优先使用字符转义,然后再使用正则表达式里面的转义。举个例子
#!/usr/bin/env python
# coding=utf-8
import re
string = '3\8'
m = re.search('(\d+)\\\\', string)
if m is not None:
print m.group(1) # 结果为:3
n = re.search(r'(\d+)\\', string)
if n is not None:
print n.group(1) # 结果为:3
1)'\\\\'的过程:
先进行“字符串转义”,前两个反斜杠和后两个反斜杠分别被转义成了一个反斜杠;即“\\|\\”被转成了“\|\”(“|”为方便看清,请自动忽略)。“字符串转义”后马上进行“正则转义”,“\\”被转义为了“\”,表示该正则式需要匹配一个反斜杠。
2)r'\\'的过程:
由于原始字符串中所有字符直接按照字面意思来使用,不转义特殊字符,故不做“字符串转义”,直接进入第二步“正则转义”,在正则转义中“\\”被转义为了“\”,表示该正则式需要匹配一个反斜杠。
所以我们在 字符串前 加上 r来 取消字符转义,来保证不会出现问题 如下:
>>> re.match(r'^\d{3}\-\d{3,8}$', '010-12345')
<_sre.SRE_Match object; span=(0, 9), match='010-12345'>
上面的 \- 代表匹配 - ,但这个不是因为 \ 是转义字符,而是因为在正则表达式中 \- 就代表匹配 - 。
精准匹配
字符含义
\d 匹配一个数字
\w 匹配一个数字或一个字母
\s 匹配一个空格
. 匹配任意一个字符
* 匹配任意字符且任意个数,如 \s* 匹配任意多个空格包括0
+ 匹配0或1个任意字符,如 \d+ 匹配0或1个数字
{n} 表示n个字符
{n,m} 表示n-m个字符
例子:
\d{3}\s+\d{3,8}
我们来从左到右解读一下:
\d{3}表示匹配3个数字,例如'010';
\s可以匹配一个空格(也包括Tab等空白符),所以\s+表示至少有一个空格,例如匹配' ',' '等;
\d{3,8}表示3-8个数字,例如'1234567'。
更精准的匹配
[] 表示范围
例一:
[0-9a-zA-Z\_]
与字符串的第一个字符进行匹配,判断其第一个字符是否是 数字 或 字母(大小写均可) 或 下划线
例二:
[0-9a-zA-Z\_]+
从字符串的第一个字符开始进行匹配,直到遇到的字符非数字、字母、下划线为止。
说白了只要第一个字符是数字 或字母或下划线就匹配成功。
例三:
[a-zA-Z\_][0-9a-zA-Z\_]*
可以匹配由字母或下划线开头,后接任意个由一个数字或字母或者下划线组成的字符串。
例四:
[a-zA-Z\_][0-9a-zA-Z\_]{0, 19}
更精确地限制了变量的长度是1-20个字符(前面1个字符+后面最多19个字符)。
^ 后面的正则表达式符号用来匹配字符串的第一个字符
$ 前面的正则表达式符号用来匹配字符串的最后一个字符
例: r'^\d{3}\-\d{3,8}$'
代表 前三个字符为数字 加上一个 - 再加上 3~8个数字
正则表达式与split配合使用
# 我们想根据空格将 一个字符串 切分成 字符数组
>>> 'a b c'.split(' ') # ab之间一个空格,bc之间两个空格,小括号里一个空格。
['a', 'b', '', 'c'] # 结果发现由于 空格个数 不一样,无法真正做到按到空格来划分字符串
我们将正则表达式与split相结合
# 使用re模块的split函数
>>> re.split(r'\s+','a b c') # 第一个参数 r'\s+' 用来匹配 1个或多个空格
['a', 'b', 'c']
无论多少个空格都可以正常分割。加入,
试试:
>>> re.split(r'[\s\,]+', 'a,b, c d')
['a', 'b', 'c', 'd']
再加入;
试试:
>>> re.split(r'[\s\,\;]+', 'a,b;; c d')
['a', 'b', 'c', 'd']
分组
re.split 函数可以将一个字符串 根据正则表达式匹配到的字符 分为多个字符串 从而放入一个 list 中
re.match().groups() 函数可以将 根据正则表达式匹配 提取出某些 从而放入一个 tuple 中
用()
表示的就是要提取的分组(Group)。比如:
^(\d{3})-(\d{3,8})$
分别定义了两个组,可以直接从匹配的字符串中提取出区号和本地号码:
>>> re.match(r'^(\d{3})-(\d{3,8})$', '010-12345').groups() # 首先用正则表达式与字符串匹配,如果匹配成功,将与小括号括起来的部分对应的字符串提取出来放入tuple中
('010', '12345')
>>> m = re.match(r'^(\d{3})-(\d{3,8})$', '010-12345')
>>> m
<_sre.SRE_Match object; span=(0, 9), match='010-12345'>
>>> m.group(0) # 也可以通过这种方式来获取,0 返回的是完整的字符串
'010-12345'
>>> m.group(1) # 1 代表 tuple中的第一个元素,往后类推
'010'
>>> m.group(2)
'12345'
贪婪匹配
最后需要特别指出的是,正则匹配默认是贪婪匹配,也就是匹配尽可能多的字符。举例如下,匹配出数字后面的0
:
>>> re.match(r'^(\d+)(0*)$', '102300').groups()
('102300', '')
# 分析:
# ^(\d+) 匹配以数字开头同时向后匹配多个数字
# (0*)$ 匹配以0结尾的字符串
# 小括号代表提取出 末尾最后几个0 ,以及其前半部分的数字
# 但结果显然不是我们想要的
# 原因:
# (\d+) 采取了贪婪匹配,其从第一个数字一直匹配到了最后一个
# 所以 (0*) 只有在 正则匹配的时候发挥了作用,而实际调用groups函数时并没有提取出字符
必须让\d+
采用非贪婪匹配(也就是尽可能少匹配),才能把后面的0
匹配出来,加个?
就可以让\d+
采用非贪婪匹配:
>>> re.match(r'^(\d+?)(0*)$', '102300').groups()
('1023', '00')