目录
一、正式表达式
1.概念和组成
2.字符范围和量词
2.1 [xxx]的用法
2.2 匹配汉字
2.3量词的用法
二、正则表达式的函数
1.re.match函数
2.re.search函数
re.match与re.search的区别
3.re.findall函数
4.re.finditer函数
5.re.sub 替换匹配的子串
三、边界符号
四、分组(...)
re.findall和分组
五、| 的用法(或)
六、贪婪模式和懒惰模式
七、“匹配对象”的函数
一、正式表达式
1.概念和组成
正则表达式是一个特殊的字符序列,它能帮助你方便的检查一个字符串是否与某种模式匹配。
字符/组合 | 匹配的模式 | 正则表达式 | 匹配的字符串 |
. | 代表任何一个字符,除了换行符(\n),包括汉字(多行匹配方式下也能匹配\n) | 'a.b' | 'acb' 'adb' 'a(b' …… |
* | 量词。表示它左边的字符可以出现0~n次 | 'a*b' | 'b' 'ab' 'aaaab' …… |
?(英文问号) | 量词。表示它左边的字符必须出现0次或1次 | 'ka?b' | 'kb' 'kab' |
+ | 量词。表示它左边的字符必须出现1次或n次 | 'ka+b' | 'kab' 'kaaaab' |
{m} | 量词。m是整数。表示它左边的字符必须且只能出现m次 | 'ka{3}b' | 'kaaab' |
{m,n} | 量词。m,n是整数。表示它左边的字符必须出现至少m次最多n次。n也可以不写,表示出现次数没有上限(如{3,}) | 'ka{1,3}b' | 'kab' 'kaab' 'kaaab' |
\d | 一个数字字符,等价于[0-9] | 'a\db' | 'a2b' 'a1b' …… |
\D | 一个非数字字符,等价于[^\d],[^0-9] (^表示非) | 'a\Db' | 'acb' …… |
\s | 一个空白字符,如空格,\t,\r,\n等 | 'a\sb' | 'a b' 'a\nb' …… |
\S | 一个非空白字符 | 'a\Sb' | 'akb' …… |
\w | 一个单词字符:包括汉字或大小写英文字母,数字,下划线,或者其他语言的文字 | 'a\wb' | 'a_b' 'a中b' …… |
\W | 一个不是单词字符的字符 | 'a\Wb' | 'a?b' |
| | A|B表示能匹配A或能匹配B均算能匹配 | 'ab|c' | 'ab' 'c' |
^ | (字符串)行的开始 ^first 表示行以first开头 |
$ | (字符串)行的结尾 last$ 表示行以last结尾 |
print("\\s\S\w\W\d\D")
#Python字符串中,\s等不是转义字符,都是两个字符
#>>\s\S\w\W\d\D
正则表达式中常见的特殊字符有以下几个:
. + ? $ [] () ^ {} \
如果要在正则表达式中表示这几个字符本身,就应该在其前面加“\”
正则表达式 -- 匹配的字符
'a\$b' -- 'a$b'
'a\\\\b' -- 'a\\b' (注意:在Python中“\\”表示一个“\”,所以此字符串长度为3,中间那个字符是'\',即 r'a\b')
r'a\\b' -- r'a\b' (r'a\b'等价于 'a\\b' )
特殊字符使用反斜杠引导,例如”\r"、"\n"、"\t"、"\"分别表示回车、换行、制表符号与反斜线自己本身.
2.字符范围和量词
2.1 [xxx]的用法
[] 内的元字符不起作用,只表示普通字符。
^放在[]中表示排除的意思(非)
[a2c] | 匹配'a','2','c'之一 | 's[a2c]k' | 'sak' 's2k' 'sck' |
[a-z A-Z] | 匹配任一英文字母 | 'b[a-z A-Z]k' | 'bak' bWk' …… |
[\da-z\?] | 匹配一个数字或小写英文字母或'?' | 'b[\da-z\?]k' | 'b0k' 'bck' 'b?k' |
[^abc] | 匹配一个非'a' , 'b' , 'c' 之一的字符 | 'b[^abc]k' | 匹配所有能匹配'b.k'的字符串,除了: 'bak' 'bbk' 'bck' |
[^a-f0-3] | 匹配一个非英文字母'a'到'f',也非数字'0'到'3'的字符 | 略 | 略 |
2.2 匹配汉字
汉字的unicode编码范围是 4e00-9fa5(16进制),因此[\u4e00-\u9fa5] 即表示一个汉字。
(16进制前要加“\u”)
如:\u4e00 :表示“一”
2.3量词的用法
'.+' | 匹配任意长度不为0且不含'\n'的字符串。'+'表示左边的'.'代表的任意字符出现1次或n次。不要求出现的字符都一样。 |
'.*' | 匹配任意不含'\n'的字符串,包括空串 |
'[\dac]+' | 匹配长度不为0的由数字或'a','c'构成的串,如'451a' , 'a21c78ca' |
'\w{5}' | 匹配长度为5的由字母或数字或汉字构成的串,如'高达abc' , '22我a1' |
例:
[1-9]\d* :正整数([1-9]表示数字1-9任意一个,“\d”表示数字等价于[0-9],“*”表示它左边的字符可以出现0~n次)(即[1-9]打头,后面跟0~n个数字)
-[1-9]\d* :负整数
-?[1-9]\d*|0 : 整数(|表示或,“?”表示它左边的字符必须出现0次或1次)
[1-9]\d*|0 :非负整数
-?([1-9]\d*\.\d*[1-9] | 0\.\d*[1-9] |
二、正则表达式的函数
re 模块使 Python 语言拥有全部的正则表达式功能。
1.re.match函数
语法:re.match(pattern, string, flags=0)
- 从字符串的起始位置匹配一个模式pattern,若起始位置匹配成功则返回一个匹配对象,否则返回 none
pattern | 匹配的正则表达式 |
string | 要匹配的字符串。 |
flags | 标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。如: re.M | re.I 表示忽略大小写,且多行匹配 I是 i 的大写字母 |
import re
def match(pattern,string):
x = re.match(pattern,string)
if x != None:
print(x.group()) #x.group是匹配上的字符串
else:
print("None")
match("a c","a cdkgh") #>>a c
match("abc","kabc") #>>None 虽然有abc,但不是在起始位置
match("a\tb*c","a\tbbccde") #>>a bbc “\t”表示制表符(这里为空格),b出现0次或任意多次,然后跟c
match("a.?b.*","aebcdf") #>>aebcdf
2.re.search函数
语法:re.search(pattern, string, flags=0)
- 查找字符串中可以匹配成功的子串
- 若匹配成功,则返回第一个成功的匹配对象,否则返回None。
import re
print(re.search('www', 'www.runoob.com').span()) # 在起始位置匹配,输出子串起止位置
print(re.search('com', 'www.runoob.com').span()) # 不在起始位置匹配
#>>(0, 3)
#>>(11, 14) (后面字符串中的索引,从0开始)
import re
def search(pattern,string):
x = re.search(pattern,string)
if x != None:
print(x.group(),x.span()) #输出子串及起止位置
else:
print("None")
search("a.+bc*","dbaegsfbcef") #>>aegsfbc (2, 9)
search("\([1-9]+\)","ab123(0456)(789)45ab") #>>(789) (11,16) “\(”表示“(” ; “\)”表示“)”
re.match与re.search的区别
re.match只匹配字符串的开始,如果字符串开始不符合正则表达式,则匹配失败,函数返回None;而re.search匹配整个字符串,直到找到一个匹配。
3.re.findall函数
语法:re.findall(pattern, string, flags=0)
- 查找字符串中所有和模式匹配的子串(不重叠)放入列表。一个子串都找不到就返回空表[ ]
注:返回的是列表
import re
print(re.findall('\d+',"this is 334 what me 774gw")) #>>['334', '774']
print(re.findall('[a-zA-Z]+',"A dog has 4 legs.这是true")) #>>['A', 'dog', 'has', 'legs', 'true']
print(re.findall('\d+',"this is good.")) #>>[]
import re
pattern = r'mr_\w+'
print(pattern) # >>mr_\w+ r+字符串表示字符串里面的转义字符木有用
string = 'MR_SHOP mr_shop'
match = re.findall(pattern,string,re.I) # re.I 表示不区分英文字母大小写
print(match) # >>['MR_SHOP', 'mr_shop']
4.re.finditer函数
语法:re.finditer(pattern, string, flags=0)
- 查找字符串中所有和模式匹配的子串(不重叠),每个子串对应于一个匹配对象,返回匹配对象的序列(准确说是“可调用迭代器”)
import re
s = '233[32]88ab<433>(21)'
m = '\[\d+\]|<\d+>' #|表示或 ,<>表示尖括号
for x in re.finditer(m,s):
print(x.group(),x.span())
i = 0
for y in re.finditer(m,"aaaaa"):
i += 1 #不会被执行
#>>[32] (3, 7)
#>><433> (11, 16)
5.re.sub 替换匹配的子串
语法:re.sub(模式串,替换串,母串)
import re
str = re.sub('\d+',"...","abc13de4fg") #将在母串中与模式串匹配的子串用替换串代替
print(str) #>>abc...de...fg
print(re.sub('\d+',"","abc13de4fg")) #>>abcdefg
print(re.sub('eating',"sleeping","I love eating!")) #>>I love sleeping!
6. re.split()分割字符串
语法:re.split(pattern, string, [maxsplit][flags=0])
maxsplit -- 可选参数,表示最大的拆分次数
import re
pat = r'[?|&]' #注意pattern是字符串哦,要加引号
url = 'http://www.mingrisoft.com/login.jps?username="mr"&pwd="mrsoft"'
result = re.split(pat,url)
print(result) #>>['http://www.mingrisoft.com/login.jps', 'username="mr"', 'pwd="mrsoft"']
三、边界符号
\A | 表示字符串的左边界,即要求从此往左边不能有任何字符 |
\Z | 表示字符串的右边界,即要求从此往右边不能有任何字符 |
^ | 与\A同。但多行匹配模式下还可以表示一行文字的左边界 |
$ | 与\Z同。但多行匹配模式下还可以表示一行文字的右边界 |
\b | 表示此处应为单词的左边界或右边界,即不可是单词字符 |
\B | 表示此处不允许是单词的左边界或右边界,即必须是单词字符 |
- 边界符号本身不会和任何字符匹配
- Python中字符串'\A' , '\Z','\B' 都是两个字符,而不是像'\n'那样的一个字符
- 正则表达式的边界符号'\b'是两个字符。但是在Python字符串中,是一个字符。因此在正则表达式中使用边界符号\b,要写'\\b'。如果写成'\\\\b',则连续的两个'\'被看作是一个普通的'\',不会和后面的'b'一起被当作字符组合,变成边界符号'\b'
print("\A\Z") #>>\A\Z
pt = "ka\\b.*" #表示ka的左边不能是单词字符(单词字符即)
search(pt,"ka") #>>ka
search(pt,"kax") #>>None 因为ka的左边x是单词字符
search(pt,"ka?d") #>>ka?d ?不是单词字符,d满足“.”
pt = ".*\\bka\\b" #表示ka的左边、右边都不能是单词字符
search(pt,"ka") #>>ka
search(pt,"ska?") #>>None
search(pt,"b?ka?") #>>b?ka
m = r"\bA.*N\b T" #等价于m = "\\bA.*N\b T"
四、分组(...)
括号中的表达式是一个分组。多个分组按左括号从左到右从1开始依次编号
import re
x = re.search('[a-z]+(\d+)[a-z]+',"ab 123d hello553world47") #表示:一个或多个小写字母 一个或多个数字 一个或多个小写字母 即hello553world满足
print(x.group(1)) #>>553
print(x.group()) #>>hello553world
m = "(((ab*)c)d)e" #即表示多个分组,要按左括号从左到右从1开始分组 (((ab*)c)d)e即1号分组,((ab*)c)d即2号分组,……
r = re.match(m,"abcdefg")
print(r.group()) #>>abcde
print(r.group(0)) #>>abcde group(0)等价于group()
print(r.group(1)) #>>abcd
print(r.group(2)) #>>abc
print(r.group(3)) #>>ab
print(r.groups()) #>>('abcd', 'abc', 'ab')
使用 group(num) 或 groups() 匹配对象函数来获取匹配表达式。
匹配对象方法 | 描述 |
group(num=0) | 匹配的整个表达式的字符串,group() 可以一次输入多个组号,在这种情况下它将返回一个包含那些组所对应值的元组。 |
groups() | 返回一个包含所有小组字符串的元组,从 1 到 所含的小组号。 |
在分组的右边可以通过分组的编号引用该分组所匹配的子串
import re
m = r'(((ab*)c)d)e\3' #r表示字符串里的'\'不再转义 等价于m = '(((ab*)c)d)e\\3'
#要求 ab*cde后面跟着3号分组在本次匹配中匹配上的子串
r = re.match(m,"abbcdeabbbkfg") #最后3个b(bbb)少一个b则不能匹配
print(r.group(3)) #>>abb
print(r.group()) #>>abbcdeabb
分组作为一个整体,后面可以跟量词
import re
m = "(((ab*)+c)d)e"
r = re.match(m,"ababcdefg")
print(r.groups()) #>>('ababcd', 'ababc', 'ab') 即分别表示1号分组,2号分组,3号分组
r = re.match(m,"abacdefg")
print(r.groups()) #>>('abacd', 'abac', 'a')
#不要求分组的多次出现必须匹配相同的字符串
re.findall和分组
在正则表达式中没有分组时,re.findall返回所有匹配子串构成的列表。有且只有一个分组时,re.findall返回的是一个子串的列表,每个元素是一个匹配子串中分组对应的内容
import re
m = '[a-z]+(\d+)[a-z]+'
x = re.findall(m,"13 bc12de ab11 cd320ef") #满足条件的m:bc12de cd320ef
print(x) #>>['12', '320']
在正则表达式中有超过一个分组时,re.findall返回的是一个元组的列表,每个元组对应于一个匹配的子串,元组里的元素,依次是1号分组、2号分组、3号分组……匹配的内容
import re
m = '(\w+) (\w+)'
r = re.match(m,"hello world")
print(r.groups()) #>>('hello', 'world')
print(r.group(1)) #>>hello
print(r.group(2)) #>>world
r = re.findall(m,"hello world,this is very good")
#找出由所有能匹配的子串的groups()构成的元组,互相不重叠
print(r) #>>[('hello', 'world'), ('this', 'is'), ('very', 'good')]
五、| 的用法(或)
表示“或”,如果没有放在“()”中,则起作用的范围是直到整个正则表达式开头或结尾或另一个“|”
"\w{4}ce|c\d{3}|p\w"
从左到右短路匹配(匹配上一个后就不计算是否还能匹配后面的)
#从左到右短路匹配(匹配上一个后就不计算是否还能匹配后面的)
import re
pt = "\d+\.\d+|\d+"
print(re.findall(pt,"12.34 this is 125")) #>>['12.34', '125']
pt = "aa|aab"
print(re.findall(pt,"aabcdeaa12aab")) #>>['aa', 'aa', 'aa'] 因为aa已经匹配上了,所以aab一直匹配不了
'|' 也可以用于分组中,起作用的范围仅限于分组内
import re
m = "(((ab*)+c|12)d)e"
print(re.findall(m,'ababcdefgkk12dek'))
#>>[('ababcd','ababc','ab'),('12d','12','')]
六、贪婪模式和懒惰模式
量词+,*,?,{m,n}默认匹配尽可能长的子串
import re
print(re.match("ab*","abbbbk").group()) #>>abbbb
print(re.findall("<h3>(.*)</h3>","<h3>abd</h3><h3>bcd</h3>")) #>>['abd</h3><h3>bcd']
在量词 +,*,?,{m,n}后面加“?”则匹配尽可能短的字符串
import re
m = "a.*?b"
for k in re.finditer(m,"aabab"):
print(k.group(),end=" ") #>>aab ab
七、“匹配对象”的函数
- 使用 group(num) 或 groups() 匹配对象函数来获取匹配表达式。
匹配对象方法 | 描述 |
group(num=0) | 匹配的整个表达式的字符串,group() 可以一次输入多个组号,在这种情况下它将返回一个包含那些组所对应值的元组。group() <==> group(0) |
groups() | 返回一个包含所有小组字符串的元组,从 1 到 所含的小组号。 |
- groupdict() :
-
start([group])
方法用于获取分组匹配的子串在整个字符串中的起始位置(子串第一个字符的索引),参数默认值为 0; -
end([group])
方法用于获取分组匹配的子串在整个字符串中的结束位置(子串最后一个字符的索引+1),(终点位置不算)参数默认值为 0; -
span([group])
方法返回(start(group), end(group))
。
import re
m = re.match(r'(\w+) (\w+)(.)','hello world!ss') #第1个分组“(\w+)”匹配“hello",第2个分组“(\w+)”匹配“world”,第3个分组“(.)”匹配“!“
print(m.string) #>>hello world!ss string表示母串
print(m.lastindex) #>>3 lastindex表示在整个母串中最后一个被匹配的分组编号,从左到右从1开始
print(m.group(0,1,2,3)) #>>('hello world!', 'hello', 'world', '!')
print(m.group()) #>>hello world!
print(m.groups()) #>>('hello', 'world', '!') 相当于group(1,2,3)
print(m.start()) #>>0
print(m.start(2)) #>>6 第2个分组的起始位置”w“的索引 索引从0开始数
print(m.end()) #>>12
print(m.end(2)) #>>11 子串最后一个字符的索引+1),(终点位置不算)
print(m.span()) #>>(0,12)
print(m.span(2)) #>>(6,11)