python 正则表达式


本章主题:

  • 介绍
  • 特别的字符和符号
  • 正则表达式与Python
  • re模块

一. 介绍

正则表达式(RE)是一些由字符和特殊符号组成的模式,方便检查一个字符串是否与某种模式匹配。
Input--->RE Filter--->Output

核心笔记 :查找与匹配的比较
在Python中,有两种主要方法完成模式匹配:搜索(searching)和匹配(matching)。
1. 搜索,即在字符串任意部分中查找匹配的模式,通过 search()函数或方法来实现。
2. 匹配,指判断一个字符串能否从起始处全部或部分的匹配某个模式。调用 match()函数或方法实现的。

二. 正则表达式使用的特殊符号和字符

常用的元字符(metacharacters)——特殊字符和符号

符号 说明 举例
literral 匹配字符串的值 foo
re1|re2 匹配正则表达式re1或re2 foo|bar
. 匹配任何字符(换行符除外) b.b
^ 匹配字符串的开始 ^Dear
$ 匹配字符串的结尾 /bin/*sh$
* 匹配前面出现的正则表达式零次或多次 [A-Za-z0-9]*
+ 匹配前面出现的正则表达式一次或多次 [a-z]+.com
? 匹配前面出现的正则表达式零次或一次 goo?
匹配前面出现的正则表达式N次 [0-9]
匹配重复出现M次到N次的正则表达式 [0-9]
[...] 匹配字符组里出现的任意一个字符 [aeiou]
[..x-y..] 匹配从字符x到y中的任意一个字符 [0-9],[a-z],[A-Z]
[^...] 不匹配此字符串中出现的任何一个字符,包括某一范围的字符 [^A-Za-z0-9]
(...) 匹配封闭括号中正则表达式RE,并 保存为子组 ([0-9]{3})?,f(00
*?,+?,??,{m,n}? 用于上面出现的任何“非贪婪”模式重复匹配次数符号 .*?[a-z]
\d 匹配任何数字,和[0-9]一样(\D是\d的反义:任何非数字) data\d+.txt
\w 匹配任何数字字母字符,和[0-9A-Za-z]相同(\W是\w的反义) [A-Za-z]\w+
\s 匹配任何空白符,和[\n\t\r\v\f]相同,(\S是\s的反义) of\sthe
\b 匹配单词边界(\B是\b的反义) \bThe\b
\nn 匹配已保存的子组 price: \16
\c 逐一匹配特殊字符c(即,取消它的特殊含义,按字面匹配) . \ *
\A (\Z) 匹配字符串的起始(结束) \ADear

三. re模块

常见的正则表达式函数与方法

函数/方法 描述
compile(pattern,flags=0) 对正则表达式模式pattern进行编译,flags是可选标识符,并返回一个regex对象
match(pattern,string,flags=0) 尝试用正则表达式模式pattern匹配字符串string,flags是可选标志符,如果匹配成功,则返回一个匹配对象;否则返回None。
search(pattern,string,flags=0) 在字符串string中查找正则表达式模式pattern的第一次出现,flags是可选标识符,如果匹配成功,则返回一个匹配对象;否则返回None。
findall(pattern,string[,flags]) 在字符串string中查找正则表达式模式pattern的所有(非重复)出现;返回一个匹配对象的列表
finditer(pattern,string[,flags]) 和findall()相同,但返回的不是列表而是迭代器;对于每个匹配,该迭代器返回一个匹配对象
split(pattern,string,max=0) 根据正则表达式pattern中的分隔符把字符string分割为一个列表,返回成功匹配的列表,最多分割max次
sub(pattern,repl,string,max=0) 把字符串string中所有匹配正则表达式pattern的地方替换成字符串repl,如果max的值没有给出,则对所有匹配的地方进行替换
group(num=0) 返回全部匹配对象(或指定编号是num的子组)
groups() 返回一个包含全部匹配的子组的元组(如果没有成功匹配,就返回一个空元组)

3.1 使用compile()编译正则表达式

大多数 re 模块函数都可以作为 regex 对象的方法。注意,尽管我们建议预编译,但它并不是必需的。如果你需要编译,就用方法,如果不需要,可以使用函数。幸运的是无论你用哪种方式-函数还是方法,名字都是相同的。

compile 函数用于编译正则表达式,生成一个正则表达式( Pattern )对象,供 match() 和 search() 这两个函数使用。
语法格式为:
re.compile(pattern[, flags])


flags : 可选,表示匹配模式,比如忽略大小写,多行模式等,具体参数为:
    re.I 忽略大小写
    re.L 表示特殊字符集 \w, \W, \b, \B, \s, \S 依赖于当前环境
    re.M 多行模式
    re.S 即为 . 并且包括换行符在内的任意字符(. 不包括换行符)
    re.U 表示特殊字符集 \w, \W, \b, \B, \d, \D, \s, \S 依赖于 Unicode 字符属性数据库
    re.X 为了增加可读性,忽略空格和 # 后面的注释

1.
>>> import re
>>> pattern = re.compile(r'\d+')     # 用于匹配至少一个数字
>>> m = pattern.match('one12twothree34four')   # 查找头部,没有匹配
>>> print(m) 
None
>>> m = pattern.match('one12twothree34four',2,10)  # 从'e'的位置开始匹配,没有匹配
>>> print(m)
None
>>> m = pattern.match('one12twothree34four',3,10)  # 从'1'的位置开始匹配,正好匹配
>>> print(m)  # 返回一个 Match 对象
<_sre.SRE_Match object at 0x7fe2a7630440>
>>> m.group()
'12'
>>> m.group(0)
'12'
>>> m.start(0)
3
>>> m.end(0)
5
>>> m.span(0)
(3, 5)

在上面,当匹配成功时返回一个 Match 对象,其中:
    group([group1, …]) 方法用于获得一个或多个分组匹配的字符串,当要获得整个匹配的子串时,可直接使用 group() 或 group(0);
    start([group]) 方法用于获取分组匹配的子串在整个字符串中的起始位置(子串第一个字符的索引),参数默认值为 0;
    end([group]) 方法用于获取分组匹配的子串在整个字符串中的结束位置(子串最后一个字符的索引+1),参数默认值为 0;
    span([group]) 方法返回 (start(group), end(group))。


2.
>>>import re
>>> pattern = re.compile(r'([a-z]+) ([a-z]+)', re.I)   # re.I 表示忽略大小写
>>> m = pattern.match('Hello World Wide Web')
>>> print m                               # 匹配成功,返回一个 Match 对象
<_sre.SRE_Match object at 0x10bea83e8>
>>> m.group(0)                            # 返回匹配成功的整个子串
'Hello World'
>>> m.span(0)                             # 返回匹配成功的整个子串的索引
(0, 11)
>>> m.group(1)                            # 返回第一个分组匹配成功的子串
'Hello'
>>> m.span(1)                             # 返回第一个分组匹配成功的子串的索引
(0, 5)
>>> m.group(2)                            # 返回第二个分组匹配成功的子串
'World'
>>> m.span(2)                             # 返回第二个分组匹配成功的子串
(6, 11)
>>> m.groups()                            # 等价于 (m.group(1), m.group(2), ...)
('Hello', 'World')
>>> m.group(3)                            # 不存在第三个分组
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: no such group

3.2 匹配对象 和 group(), groups() 方法

匹配对象是在 match()或 search()被成功调用之后所返回的结果。匹配对象有两个主要方法:group() 和 groups().
group()方法或者返回所有匹配对象或是根据要求返回某个特定子组。groups()则很简单,它返
回一个包含唯一或所有子组的元组。如果正则表达式中没有子组的话, groups() 将返回一个空元组,而 group()仍会返回全部匹配对象。

3.3 用match()匹配字符串

match()函数是从字符串的开头对模式进行匹配。如果匹配成功,就返回一个匹配对象,而如果匹配失败了,就返回 None。匹配对象的 group() 方法可以用来显示那个成功的匹配。

函数语法:
re.match(pattern, string, flags=0)


1.
import re

m = re.match('foo','foo')  # 模式匹配字符串
if m is not None:          # 如果成功,显示匹配
    print(m.group())
    
2.    
import re

m = re.match('fooda','food on the table').group()
print(m)
如果匹配失败,会引发一个AttributeError异常


2.
#!/usr/bin/python
import re
 
line = "Cats are smarter than dogs"
 
matchObj = re.match( r'(.*) are (.*?) .*', line, re.M|re.I)
 
if matchObj:
   print "matchObj.group() : ", matchObj.group()
   print "matchObj.group(1) : ", matchObj.group(1)
   print "matchObj.group(2) : ", matchObj.group(2)
else:
   print "No match!!"

3.4 search() 在一个字符串中查找一个模式

search()查找字符串中模式首次出现的位置。如果搜索到成功的匹配,会返回一个匹配对象,否则返回 None。

re.search(pattern, string, flags=0)
1.
import re

m = re.search('foo','seafood')
if m is not None:
    print(m.group())
    
    
match()从字符串开头进行匹配模式    
import re

m = re.match('foo','seafood')
if m is not None:
    print(m.group())
    


#!/usr/bin/python
import re
 
line = "Cats are smarter than dogs";
 
searchObj = re.search( r'(.*) are (.*?) .*', line, re.M|re.I)
 
if searchObj:
   print "searchObj.group() : ", searchObj.group()
   print "searchObj.group(1) : ", searchObj.group(1)
   print "searchObj.group(2) : ", searchObj.group(2)
else:
   print "Nothing found!!"

3.5 re.match与re.search的区别

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

import re

line = "Cats are smarter than dogs";

matchObj = re.match(r'dogs', line, re.M | re.I)
if matchObj:
    print("match --> matchObj.group() : ", matchObj.group())
else:
    print("No match!!")

matchObj = re.search(r'dogs', line, re.M | re.I)
if matchObj:
    print("search --> matchObj.group() : ", matchObj.group())
else:
    print("No match!!")

3.6 匹配多个字符串(|)

import re

bt = 'bat|bet|bit'     # 匹配模式
m = re.match(bt,'bat')   # 匹配到bat
if m is not None:
    print(m.group())

m = re.match(bt,'blt')   #没有匹配blt的模式
if m is not None:
    print(m.group())

m = re.match(bt,'He bit me')   #不匹配字符串
if m is not None:
    print(m.group())

m = re.search(bt,'He bit me')   # 搜索到'bit'
if m is not None:
    print(m.group())

3.7 匹配任意单个字符(.)

以下的例子中,我们将说明点号是不能匹配换行符或非字符(即,空字符串)的:

import re

anyend = '.end'
m = re.match(anyend,'bend')  # 点号匹配b
if m is not None:
    print(m.group())

m = re.match(anyend,'end')   # 没有字符匹配
if m is not None:
    print(m.group())

m = re.match(anyend,'\nend')   # 匹配字符(\n)除外
if m is not None:
    print(m.group())

m = re.search('.end','The end.')   # 匹配' '
if m is not None:
    print(m.group())

下面的例子是来搜索一个真正点号(小数点)的正则表达式,在正则表达式中,用反斜线对它进
行转义,使点号失去它的特殊意义:

import re

patt314 = '3.14'    # 正则表达式点号
pi_patt = '3\.14'   # 浮点(小数点)
m = re.match(pi_patt,'3.14')  #完全匹配
if m is not None:
    print(m.group())

m = re.match(patt314,'3014')      # 点号匹配'0'
if m is not None:
    print(m.group())

m = re.match(patt314,'3.14')     # 点号匹配'.'
if m is not None:
    print(m.group())

3.8 创建字符集合([])

import re

m = re.match('[cr][23][dp][o2]','c3po')  # 匹配'c3po'
if m is not None:
    print(m.group())

m = re.match('[cr][23][dp][o2]','c2do')  # 匹配'c2do'
if m is not None:
    print(m.group())

m = re.match('r2d2|c3po','c2do')  # 匹配'c2do'
if m is not None:
    print(m.group())

m = re.match('r2d2|c3po','r2d2')  # 匹配'r2d2'
if m is not None:
    print(m.group())

3.9 重复、特殊字符和子组

import re

patt = '\w+@(\w+\.)?\w+\.com'
m = re.match(patt,'nobody@xxx.com').group()
print(m)

n = re.match(patt,'nobody@www.xxx.com').group()
print(n)

子组

>>> m = re.match('ab', 'ab')  # 无子组
>>> m.group() 
'ab'
>>> m.groups()  # 所有匹配的子组
()
>>>
>>> m = re.match('(ab)', 'ab') #一个子组
>>> m.group() #所有匹配
'ab'
>>> m.group(1) #匹配的子组 1
'ab'
>>> m.groups() #所有匹配子组Edit By Vheavens
Edit By Vheavens
('ab',)
>>>
>>> m = re.match('(a)(b)', 'ab') #两个子组
>>> m.group() 
'ab'
>>> m.group(1) # 匹配的子组 1
'a'
>>> m.group(2) # 匹配的子组 2
'b'
>>> m.groups() # 所有匹配子组的元组
('a', 'b')
>>>
>>> m = re.match('(a(b))', 'ab') ##两个子组
>>> m.group() #所有匹配部分
'ab'
>>> m.group(1) #匹配的子组 1
'ab'
>>> m.group(2) #匹配的子组 2
'b'
>>> m.groups() #所有匹配的子组的元组
('ab', 'b')

3.10 从字符串的开头或结尾匹配及在单词边界上的匹配

import re

m = re.search('^The','The end.')  # 匹配
if m is not None:
    print(m.group())

m = re.search('^The','end. The')  # 不在开头
if m is not None:
    print(m.group())

m = re.search(r'\bthe','bite the dog')  # 在词边界
if m is not None:
    print(m.group())

m = re.search(r'\bthe','bitethe dog')  # 无边界
if m is not None:
    print(m.group())

m = re.search(r'\Bthe','bitethe dog')  # 无边界
if m is not None:
    print(m.group())

3.11 用findall()找到每个出现的匹配部分,返回一个列表

在字符串中找到正则表达式所匹配的所有子串,并返回一个列表,如果没有找到匹配的,则返回空列表。
注意: match 和 search 是匹配一次 findall 匹配所有。

语法格式为:
findall(string[, pos[, endpos]])

.
>>> re.findall('car', 'car')
['car']
>>> re.findall('car', 'scary')
['car']
>>> re.findall('car', 'carry the barcardi to the car')
['car', 'car', 'car']

2.查找字符串中的所有数字
import re
 
pattern = re.compile(r'\d+')   # 查找数字
result1 = pattern.findall('runoob 123 google 456')
result2 = pattern.findall('run88oob123google456', 0, 10)
 
print(result1)
print(result2)

3.12 re.finditer

和 findall 类似,在字符串中找到正则表达式所匹配的所有子串,并把它们作为一个迭代器返回。

re.finditer(pattern, string, flags=0)

1.
import re

it = re.finditer(r"\d+","12a32bc43jf3")
for match in it:
    print(match.group())

3.13 用sub()进行搜索和替换

re.sub用于替换字符串中的匹配项。

re.sub(pattern, repl, string, count=0, flags=0)

1.
import re

m = re.sub('X','Mr. Smith','attn:X\nDear X,\n')
print(m)
m = re.subn('X','Mr. Smith','attn:X\nDear X,\n')
print(m)
m = re.sub('[ae]','X','abcdef')
print(m)
m = re.subn('[ae]','X','abcdef')
print(m)


2.
import re

phone = "2004-959-559"

# 删除字符串中的python注释
num = re.sub(r'#.*$',"",phone)
print("phone: ",num)

#删除非数字(-)的字符串
num = re.sub(r'\D',"",phone)
print("phone: ",num)

3. repl参数是一个函数
import re

# 将匹配的数字乘以2
def double(matched):
    value = int(matched.group('value'))
    return str(value * 2)

s = 'A23G4HFD567'
print(re.sub('(?P<value>\d+)',double,s))

3.14 用split()分割

如果分隔符没有使用由特殊符号表示的正则表达式来匹配多个模式,那 re.split()和
string.split()的执行过程是一样的,见以下的例子(在每一个冒号处分隔):

re.split(pattern, string[, maxsplit=0, flags=0])

1.
import re

m = re.split(':','str1:str2:str3')
print(m)


四 正则表达式示例

练习

1. 识别下列字符串:"bat","bit","but","hat","hit"或"hut"
import re

str = 'batshut'
patt = '[b|h][a|i|u]t'
m = re.match(patt,str)
if m is not None:
    print(m.group())

2. 匹配用一个空格分隔的任意一对单词,比如,名和姓。
import re

str = 'Mr Smith'
patt = '\w+ \w+'
m = re.match(patt,str)
if m is not None:
    print(m.group())

3.匹配用一个逗号和一个空格分开的一个单词和一个字母。例如,英文人名中的姓和名
的首字母
import re

str = 'Mr, Smith'
patt = '\w+, \w?'
m = re.match(patt,str)
if m is not None:
    print(m.group())
    
4. 匹配所有合法的Python标识符
import re

str = 'hello'
patt = '[\w|_]*'
m = re.match(patt,str)
if m is not None:
    print(m.group())
    
5. 请根据您本地关于地址的格式写法匹配一个街道地址(你写出的正则表达式要尽可能通用以匹配任意数目的表示街道名字的单词,包括类型指示)。比如,美国的街道地址使用这样的格式:1180 Bordeaux Drive. 使你写的正则表达式尽可能通用,要求能够匹配多个单词的街道名字,如:3120 De la Cruz Boulevard.

import re

str = '3120 De la Cruz Boulevard'
patt = '\d+(\s[A-Za-z]+)+'
m = re.match(patt,str)
if m is not None:
    print(m.group())
    
6. 匹配简单的以"www."开头,以".com"作结尾的 Web 域名,例如:www.yahoo.com. 附
加题:使你写的正则表达式还支持其他顶级域名:.edu, .net 等,比如:www.ucsc.edu.

import re

str = 'www.ucsc.edu'
patt = '^www\.\w+\.\w+'
m = re.match(patt,str)
if m is not None:
    print(m.group())
    
7. 匹配全体 Python 整数的字符串表示形式的集合。
import re

str = '111 222'
patt = '\d+'
m = re.match(patt,str)
if m is not None:
    print(m.group())
    
8. 匹配全体 Python 长整数的字符串表示形式的集合
import re

str = '111111L'
patt = '(\d+[1L]+)+'
m = re.match(patt,str)
if m is not None:
    print(m.group())

9. 匹配全体 Python 浮点数的字符串表示形式的集合。
import re

str = '111.11'
patt = '\d+(\.\d)*'
m = re.match(patt,str)
if m is not None:
    print(m.group())

10.匹配所有合法的电子邮件地址。
import re

str = 'www@qq.com'
patt = '\w+@\w+\.\w+'
m = re.match(patt,str)
if m is not None:
    print(m.group())
    
11. 匹配所有合法的 Web 网站地址(URLs)
import re

str = 'http://www.qq.com'
patt = r'^http://\w+(\.\w+)+'
m = re.match(patt,str)
if m is not None:
    print(m.group())



posted @ 2018-07-03 12:26  wpf926  阅读(61)  评论(0)    收藏  举报