正则表达式 为高级的文本模式匹配、抽取、与/或文本形式的搜索和替换功能提供了基础。简单地说,正则表达式(简称为 regex)是一些由字符和特殊符号组成的字符串,它们描述了模式的重复或者表述多个字符,于是正则表达式能按照某种模式匹配一系列有相似特征的字符串。换句话说,它们能够匹配多个字符串……一种只能匹配一个字符串的正则表达式模式是很乏味并且毫无作用的,不是吗?Python 通过标准库中的 re 模块来支持正则表达式
正则表达式的特殊字符列表
‘.‘ 匹配所有字符串,除\n以外
‘-’ 表示范围[0-9]
‘*‘ 匹配前面的子表达式零次或多次。要匹配 * 字符,请使用 \*。
‘+‘ 匹配前面的子表达式一次或多次。要匹配 + 字符,请使用 \+
‘^‘ 匹配字符串开头
‘$’ 匹配字符串结尾 re
‘‘ 转义字符, 使后一个字符改变原来的意思,如果字符串中有字符*需要匹配,可以\*
‘?’ 匹配前一个字符串0次或1次
‘{m}‘ 匹配前一个字符m次
‘{n,m}‘ 匹配前一个字符n到m次
‘\d‘ 匹配数字,等于[0-9]
‘\D‘ 匹配非数字,等于[^0-9]
‘\w‘ 匹配字母和数字,等于[A-Za-z0-9]
‘\W‘ 匹配非英文字母和数字,等于[^A-Za-z0-9]
‘\s‘ 匹配空白字符
‘\S‘ 匹配非空白字符
‘\A‘ 匹配字符串开头
‘\Z‘ 匹配字符串结尾
‘\b‘ 匹配单词的词首和词尾,单词被定义为一个字母数字序列,因此词尾是用空白符或非字母数字符来表示的
‘\B‘ 与\b相反,只在当前位置不在单词边界时匹配
‘(?P 分组,除了原有编号外在指定一个额外的别名
[] 是定义匹配的字符范围。比如 [a-zA-Z0-9] 表示相应位置的字符要匹配英文字符和数字。[\s*]表示空格或者*号。
Python的re正则表达式模块提供的方法
re.match(pattern, string, flags=0) #从字符串的起始位置匹配,如果起始位置匹配不成功的话,match()就返回none
re.search(pattern, string, flags=0) #扫描整个字符串并返回第一个成功的匹配
re.findall(pattern, string, flags=0) #找到RE匹配的所有字符串,并把他们作为一个列表返回
re.finditer(pattern, string, flags=0) #找到RE匹配的所有字符串,并把他们作为一个迭代器返回
re.sub(pattern, repl, string, count=0, flags=0) #替换匹配到的字符串
函数参数说明:
pattern: 匹配的正则表达式 string:要匹配的字符串
flags: 标记为,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。
repl: 替换的字符串,也可作为一个函数
count: 模式匹配后替换的最大次数,默认0表示替换所有匹配
import re
m = re.match(r‘f..‘, r‘begin fool hello‘) # match 从字符串的开始位置进行搜索,如果需从字符串任意位置进行搜索,需使用下文中的search方法
if m is not None:
print(‘found : ‘ + m.group())
else:
print(‘not found!‘)
not found!
search()函数不但会搜索模式在字符串中第一次出现的位置,而且严格地对字符串从左到右搜索。
m = re.search(r‘foo‘, ‘beginfool hello‘)
if m is not None:
print(‘found : ‘ + m.group())
else:
print(‘not found...‘)
found : foo
匹配任何单个字符串
anyend = ‘.end‘
m = re.match(anyend, ‘bend‘) # 点号匹配‘b’
if m is not None: print(m.group())
bend
m = re.match(anyend, ‘end‘) # 不匹配任何字符串
if m is not None: print(m.group())
m = re.match(anyend, ‘\nbend‘) # 除了‘\n‘之外的任何字符串
if m is not None: print(m.group())
m = re.match(anyend, ‘The end.‘) # 点号匹配‘ end’
if m is not None: print(m.group())
gorup()和groups()方法的使用
m = re.match(r‘(\w{3})-(\d{3})‘, ‘abc-123‘)
if m is not None:
print(‘m.group(): ‘ + m.group())
print(‘m.group(1): ‘ + m.group(1))
print(‘m.group(2): ‘ + m.group(2))
print(‘m.groups(): ‘ + str(m.groups()))
m.group(): abc-123
m.group(1): abc
m.group(2): 123
m.groups(): (‘abc‘, ‘123‘)
findall()查询字符串中某个正则表达式模式全部的非重复出现情况。这与 search()在执行字符串搜索时类似,但与 match()和 search()的不同之处在于,findall()总是返回一个列表。如果 findall()没有找到匹配的部分,就返回一个空列表,但如果匹配成功,列表将包含所有成功的匹配部分(从左向右按出现顺序排列)。
re.findall(‘car‘, ‘car‘)
[‘car‘]
re.findall(‘car‘, ‘scary‘)
[‘car‘]
re.findall(‘car‘, ‘carry the brcardi to the car‘)
[‘car‘, ‘car‘, ‘car‘]
finditer()和findall()返回的匹配字符串相比,finditer()在匹配对象中迭代.
s = ‘This and that.‘
re.findall(r‘(th\w+)‘, s, re.I)
[‘This‘, ‘that‘]
iter = re.finditer(r‘(th\w+)‘, s, re.I)
iter
<callable_iterator at 0x594a780>
[g.group() for g in iter] # findall 返回一个列表,而finditer返回一个迭代器
[]
有两个函数/方法用于实现搜索和替换功能:sub()和 subn()。两者几乎一样,都是将某字符串中所有匹配正则表达式的部分进行某种形式的替换。用来替换的部分通常是一个字符串,但它也可能是一个函数,该函数返回一个用来替换的字符串。subn()和 sub()一样,但 subn()还返回一个表示替换的总数,替换后的字符串和表示替换总数的数字一起作为一个拥有两个元素的元组返回。
print(re.sub(‘X‘, ‘Mr. Iceman‘, ‘attn: X\n\nDear X,\n‘))
attn: Mr. Iceman
Dear Mr. Iceman,
print(re.subn(‘X‘, ‘Mr. Iceman‘, ‘attn: X\n\nDear X,\n‘))
(‘attn: Mr. Iceman\n\nDear Mr. Iceman,\n‘, 2)
re 模块和正则表达式的对象方法 split()对于相对应字符串的工作方式是类似的,但是与分割一个固定字符串相比,它们基于正则表达式的模式分隔字符串,为字符串分隔功能添加一些额外的威力。
如果给定分隔符不是使用特殊符号来匹配多重模式的正则表达式,那么 re.split()与str.split()的工作方式相同
re.split(‘:‘, ‘str1:str2:str3‘)
[‘str1‘, ‘str2‘, ‘str3‘]
DATA = (
‘Mountain View, CA 94040‘,
‘Sunnyvale, CA‘,
‘Los Altos, 94023‘,
‘Cupertino 95014‘,
‘Palo Alto CA‘
)
for item in DATA:
print( re.split(‘, |(?= (?:\d{5}|[A-Z]{2})) ‘, item))
[‘Mountain View‘, ‘CA‘, ‘94040‘]
[‘Sunnyvale‘, ‘CA‘]
[‘Los Altos‘, ‘94023‘]
[‘Cupertino‘, ‘95014‘]
[‘Palo Alto‘, ‘CA‘]
import os
import re
with os.popen(‘tasklist /nh‘, ‘r‘) as f:
for line in list(f)[:5]:
# print(re.split(r‘\s\s+|\t‘, line.rstrip())) #pid 和会话名未分解
print(re.findall(r‘([\w.]+(?: [\w.]+)*)\s\s*(\d+)\s(\w+)\s\s*(\d+)\s\s*([\d,]+\sK)‘, line.strip()))
[]
[(‘System Idle Process‘, ‘0‘, ‘Services‘, ‘0‘, ‘24 K‘)]
[(‘System‘, ‘4‘, ‘Services‘, ‘0‘, ‘2,852 K‘)]
[(‘smss.exe‘, ‘364‘, ‘Services‘, ‘0‘, ‘1,268 K‘)]
[(‘csrss.exe‘, ‘612‘, ‘Services‘, ‘0‘, ‘6,648 K‘)]
如下以一完整示例结束本文,它以不同的方式使用正则表达式来操作字符串。首先使用该脚本为正则表达式练习创建随机数据,然后将生成的数据提取其中的数字和邮箱地址
from random import randrange, choice
from string import ascii_lowercase as lc
from datetime import datetime
import time
import re
result_data = []
# gen data
tlds = (‘com‘, ‘cn‘, ‘edu‘, ‘net‘, ‘gov‘, ‘org‘)
for i in range(randrange(4, 9)):
max_seconds = int(datetime.now().timestamp())
dtint = randrange(max_seconds)
#dtstr = str(datetime.fromtimestamp(dtint))
dtstr = ctime(dtint)
llen = randrange(4, 8)
login = ‘‘.join(choice(lc) for j in range(llen))
dlen = randrange(llen, 13)
dom = ‘‘.join(choice(lc) for j in range(dlen))
result_data.append(‘%s::%s@%s.%s::%d-%d-%d‘ % (dtstr, login, dom, choice(tlds), dtint, llen, dlen))
#print(result_data)
#test re
re_patt = ‘^(\w{3}).*::(?P<email>\[email protected]\w+.\w+)::(?P<number>\d+-\d+-\d+)‘
for item in result_data:
m = re.match(re_patt, item)
if m is not None:
print(‘*‘*30)
print(item)
print("Email: " + m.group(‘email‘))
print(‘Number: ‘ + m.group(‘number‘))
******************************
Tue Jan 28 15:34:09 1992::[email protected]::696584049-7-11
Email: [email protected]
Number: 696584049-7-11
******************************
Thu Dec 23 22:35:52 1971::[email protected]::62346952-6-7
Email: [email protected]
Number: 62346952-6-7
******************************
Sat Jan 25 11:26:50 2003::[email protected]::1043465210-6-8
Email: [email protected]
Number: 1043465210-6-8
******************************
Wed Sep 28 23:37:34 1977::[email protected]::244309054-7-10
Email: [email protected]
Number: 244309054-7-10
******************************
Sun Feb 7 12:08:11 1988::[email protected]::571205291-4-9
Email: [email protected]
Number: 571205291-4-9
******************************
Sat Aug 31 00:04:58 1996::[email protected]::841421098-4-8
Email: [email protected]
Number: 841421098-4-8
******************************
Tue Oct 9 05:32:20 1984::[email protected]::466119140-7-7
Email: [email protected]
Number: 466119140-7-7