Regular Expression称为正则表达式,以下简称为RE。
不用RE在文本中查找模式
美国电话号码的格式为###-###-###
,如果要判断号码格式是否合法,并且不用RE,需要结合isdecimal()方法。
def is_valid(phone_num):
if(len(phone_num) != 12):
return False
if phone_num[3] != '-' and phone_num[7] != '-':
return False
for s in phone_num.split('-'):
if not s.isdecimal():
return False
return True
print(is_valid('123-456-7890'))
print(is_valid('123-4#6-7890'))
如果要在一段文本中寻找电话号码,可以用msg[i:i+12]结合以上is_valid()
函数。
通过RE在文本中寻找模式
RE在re
模块中定义。因此需要import re
。
# 正则表达式\d表示数字字符
>>> regex = re.compile(r'\d\d\d-\d\d\d-\d\d\d\d')
>>> phone_number = regex.search('My number is 415-555-4242.')
>>> print(phone_number) # 如果匹配,则返回Match对象
<_sre.SRE_Match object; span=(13, 25), match='415-555-4242'>
>>> print(phone_number.group()) # group返回匹配的字符串
415-555-4242
>>> print(phone_number.span())
(13, 25)
>>> phone_number = regex.search('My number')
>>> print(phone_number) # 如果不匹配,则返回None
None
交互式RE测试参见网站:https://pythex.org/
更多正则表达式
在正则表达式中,. ^ $ * + ? { } [ ] \ | ( )
这些字符具有特殊含义,需要用\
转义。
()
表示group,例如(\d\d\d)-(\d\d\d-\d\d\d\d)
需要匹配多个group可以用管道符’|'分开,例如(patternA|patternB)
0个或1个匹配用?
,0个或多个匹配用*
,一个或多个匹配用+
。
固定次数的匹配用{n}
,例如{3}
,次数在某一区间使用{m,n}
的格式,例如{3,5}
。
示例:
>>> re.compile(r'(\d\d\d)-(\d\d\d\d)').search('123-4567').group(2)
'4567'
>>> re.compile(r'(good|bad)man').search('goodman').group()
'goodman'
>>> re.compile(r'(good|bad)man').search('goodman').group(1)
'good'
如何引用group??? 是在替换中指定吗???
贪婪与非贪婪模式匹配
默认是贪婪模式,即最长的匹配;在}
后面加?
,可指定非贪婪模式。
>>> re.compile(r'(ha){3,5}').search('hahahahaha').group()
'hahahahaha'
>>> re.compile(r'(ha){3,5}?').search('hahahahaha').group()
'hahaha'
FINDALL()方法
search()只返回第一个匹配,findall()返回所有匹配,并返回一个list:
>>> re.compile(r'(\w+)').findall('good bye!')
['good', 'bye']
>>> re.compile(r'(\w+)').search('good bye!').group()
'good'
注意不要写成(\w)+
。
字符分类
\d
表示数字字符,就是0
到9
; \D
表示非\d
。
\w
表示数字,字母和下划线; \W
表示非\w
。
\s
表示space字符,包括空格,tab和换行;\S
表示非\s
。
并非任何时候都需要group,也可以用[]
表示可匹配其中任意字符,其中的-
表示区间,|
表示或者,^
表示非。
>>> re.compile(r'[abc]').search('good bye!').group()
'b'
>>> re.compile(r'[a-z]').search('good bye!').group()
'g'
>>> re.compile(r'[a|b]').search('good bye!').group()
'b'
>>> re.compile(r'[d|b]').search('good bye!').group()
'd'
>>> re.compile(r'[^a-z]').search('goodbye6!').group()
'6'
制作自己的字符类
例如'[^aeiouAEIOU]
表示元音。(\w+)
表示单词。
脱字符和美元符
脱字符^
表示行首,美元符$
表示行末。
通配符
.
称为通配符,可匹配任意单个字符。
.*
默认匹配除换行符(\n
)外的任意模式,不过可以指定re.DOTALL将换行符也计在内。
>>> re.compile(r'.*').search('row1\nrow2').group()
'row1'
>>> re.compile(r'.*', re.DOTALL).search('row1\nrow2').group()
'row1\nrow2'
正则表达式回顾
?
, *
和+
{m}
表示正好m次匹配;{m,n}
表示m到n次匹配,m如省略表示0,n如省略表示无限。{}?
表示非贪婪模式。
.
和.*
\d
, \w
, \s
; \D
, \W
, \S
[abc]
, [^abc]
, [abc|def]
大小写不敏感的匹配
默认是大小写敏感的,指定re.I
标志为可实现大小写不敏感的匹配,例如re.compile(pattern, re.I)
。
用SUB()方法替换字符串
注意,可以用\n的形式引用第n个group。
>>> re.compile('(\d\d\d)-(\d\d\d\d)').sub(r'\1-****', '123-4567')
'123-****'
>>> re.compile('(\d\d\d)-(\d\d\d\d)').sub(r'\2-\1', '123-4567')
'4567-123'
管理复杂的正则表达式
当正则表达式较复杂,需要跨多行写时,可以指定编译的re.VERBOSE
标志以及'''
,例如
re.compile(r'''(
sub-pattern1
sub-pattern2
...
sub-patternN
)''', re.VERBOSE)
多种编译模式的组合
RE.IGNORECASE, RE.DOTALL和RE.VERBOSE都是bitmap,因此用|
组合就好。
项目: 抽取电话号码和邮件地址
略。