正则表达式
正则表达式是对字符串操作的一种逻辑公式,就是用事先定义好的一些特定字符以及这些特定字符的组合组成一个“规则字符串”,来表达对字符串的一种过滤逻辑。
正则表达式是用来匹配字符串非常强大的工具,其大致匹配过程是:
- 依次拿出表达式和文本中的字符比较;
- 如果每一个字符都能匹配则成功,一旦有匹配不成功的字符则匹配失败;
- 如果表达式中有量词或者边界,会有不同;
正则表达式的语法规则
相关注解
数量词的贪婪模式与非贪婪模式
正则表达式通常用于文本中查找匹配的字符串。Python中数量词默认是贪婪的(少数语言中可能默认非贪婪),总是尝试尽可能多的字符,而非贪婪则相反,总是匹配尽可能少的字符。例如:“ab*”,如果用于查找“abbbc”,将找到“abbb”,而非贪婪的数量词“ab*?”,将找到“a”。
反斜杠问题
大多数编程语言中正则表达式使用“\”作为转义字符,就会造成反斜杠困扰。如果需要匹配文本中的字符“\”,那么使用编程语言表示的正则表达式里将需要4个反斜杠“\\\\”,前两个和后两个分别用于在编程语言里转义为反斜杠,转换成两个反斜杠后再在正则表达式中转义一个反斜杠。Python中原生字符串很好的解决这个问题,这个例子中正则表达式可以使用 r"\\"表示,匹配一个数字的“\\d”可以写作r"\d"。
python Re 模块
pattern:一个匹配模式
#返回pattern对象
pattern = re.compile(string[,flag]) flag参数是匹配模式,取值可以使用按位或运算符‘|’表示同时生效,例如re.I | re.M。
可选值有:
re.I (IGNORECASE):忽略大小写;
re.M (MULTILINE):多行模式,改变‘^’和‘$’的行为;
re.S(DOTALL):点任意匹配模式,改变‘ . ’的行为;
re.L(LOCALE):使预定字符类 \w \W \b \B \s \S 取决于当前区域设定;
re.U(UNICODE):使预定字符类\w \W \b \B \s \S \d \D 取决于unicode定义的字符属性;
re.X(VERBOSE):详细模式;这个模式下正则表达式可以是多行,忽略空白字符,并可以加入注释;
常用的函数
(1)re.match(pattern , string[, flags])
这个方法将会从string的开头开始,尝试匹配pattern,一直向后匹配,如果遇到无法匹配的字符,立即返回None,如果匹配未结束已经到达string的末尾,也会返回None,两个结果均表示匹配失败,否则pattern匹配成功,同时匹配终止,不再对string向后匹配。
import re
pattern = re.compile(r'hello')
result1 = re.match(pattern, 'hello')
result2 = re.match(pattern, 'helloo 123')
result3 = re.match(pattern, 'helo 123')
result4 = re.match(pattern, 'hello 123')
if result1:
print(result1.group())
else:
print("1失败")
if result2:
print(result2.group())
else:
print('2失败')
if result3:
print(result3.group())
else:
print('3失败')
if result4:
print(result4.group())
else:
print('4失败')
hello
hello
3失败
hello
使用match方法返回的是一个match对象,match对象含有以下属性和方法:
属性:
- string:匹配时使用的文本;
- re:匹配时使用的pattern对象;
- pos:文本中正则表达式开始搜索的索引,值与pattern.match()和pattern.search()方法的同名参数相同;
- endpos:文本中正则表达式结束搜索的索引;
- lastindex:最后一个被捕获分组在文本中的索引,如果没有被捕获分组,则为None;
- lastgroup:最后一个被捕获分组的别名;
方法:
- group([group1,...]):获得一个或者多个分组截获的字符串,指定多个参数时将以元组形式返回。group1可以使用编号也可以使用别名,编号0代表整个匹配的子串,不填参数时,返回group(0),没有截获字符串的组返回None,截获了多次的组返回最后一次截获的子串。
- groups([default]):以元组的形式返回全部分组截获的字符串,相当于调用group(1,2,...last),default表示没有截获字符串的组以这个值代替,默认None;
- groupdict([default]):返回以有别名的组的别名为键、以该组截获的子串为值的字典,没有别名的组不包含在内;
- start([group]):返回指定的组截获的子串在string中的起始索引(子串第一个字符的索引),group默认值为0;
- end([group]):返回指定的组截获的子串在string中的结束索引(子串最后一个字符的索引+1),group默认值为0;
- span([group]):返回(start(group),end(group);
- expand(template):将匹配到的分组带入template中然后返回,template中可以使用\id或\g、\g引用分组,但不能使用编号0;\id与\g是等价的,但\10将被认为是第10个分组,如果想表达\1之后是字符'0',只能使用 \g0 ;
#匹配内容:单词+空格+单词+任意字符
m = re.match(r'(\w+) (\w+)(?P<sign>.*)','hello world!')
print("m.string:",m.string)
print('m.re:',m.re)
print('m.pos:',m.pos)
print('m.endpos:',m.endpos)
print('m.lastindx:',m.lastindex)
print('m.lastgroup:',m.lastgroup)
print('m.group():',m.group())
print('m.group(1,2):',m.group(1,2))
print('m.groups():',m.groups())
print('m.groupdict()',m.groupdict())
print('m.start(2):',m.start(2))
print('m.end(2):',m.end(2))
print('m.span(2):',m.span(2))
print(r"m.expand(r'\g \g\g'):",m.expand(r'\2 \1\3'))
m.string: hello world!
m.re: re.compile('(\\w+) (\\w+)(?P<sign>.*)')
m.pos: 0
m.endpos: 12
m.lastindx: 3
m.lastgroup: sign
m.group(): hello world!
m.group(1,2): ('hello', 'world')
m.groups(): ('hello', 'world', '!')
m.groupdict() {'sign': '!'}
m.start(2): 6
m.end(2): 11
m.span(2): (6, 11)
m.expand(r'\g \g\g'): world hello!
(2)re.search(pattern,string[, flags])
search()方法与match方法极为相似,区别在于match()函数只检测re是不是在string开始位置匹配,search()会扫描整个string查找匹配,match()只有在0位置匹配成功的话才有返回,如果不是开始位置匹配成功的话,match()就返回None;同样,search()方法的返回对象以及方法属性与match()相同;
pattern = re.compile(r'world')
match = re.search(pattern,'hello world')
if match:
print(match.group())
else:
print('failed')
world
(3)re.split(pattern, string[, maxsplit])
按照能够匹配的子串将string分割后返回列表,maxsplit用于指定最大分割次数,不指定将全部分割;
pattern = re.compile(r'\d+')
print(re.split(pattern,'one1two2three3four4'))
['one', 'two', 'three', 'four', '']
(4)re.findall(pattern,string[, flags])
搜索string,以列表形式返回全部能匹配的子串。
pattern = re.compile(r'\d+')
print(re.findall(pattern,'one1two2three3four4'))
['1', '2', '3', '4']
(5)re.finditer(pattern, string[, flags])
搜索string,返回一个顺序访问每一个匹配结果(match对象)的迭代器。
pattern = re.compile(r'\d+')
for m in re.finditer(pattern,'one1two2three3four4'):
print(m.group())
1
2
3
4
(6)re.sub(pattern,repl,string, count,flags)
使用repl替代string中每一个匹配的子串后返回替代后的字符串。当repl是一个字符串时,可以使用\id或\g、\g引用分组,但不能使用编号0;当repl是一个方法时,这个方法应当只接受一个参数(match对象),并返回一个字符串用于替换(返回的字符串中不能再引用分组)。count用于指定最多替换次数,不指定时全部替换。
pattern = re.compile(r'(\w+) (\w+)')
s = 'i say,hello world!'
print(re.sub(pattern,r'\2 \1',s))
def func(m):
return m.group(1).title()+" "+m.group(2).title()
print(re.sub(pattern,func,s))
say i,world hello!
I Say,Hello World!
re.sub共有五个参数
三个必选参数 pattern,repl,string
两个可选参数count,flags
- string,要处理的字符串
- count,限定替换的个数,默认为替换所有
- flags,匹配模式,可以使用按位或‘|‘表示同时生效,也可以在正则表达式中指定。
- re.I忽略大小写
- re.L表示特殊字符集\w,\W,\b,\B,\s,\S
- re.M表示多行模式
- re.S ‘.’包括换行符在内的任意字符
- re.U表示特殊字符集\w,\W,\b,\B,\d,\D,\s,\D
(7)re.subn(pattern,repl,string[, count]):返回(sub(repl,string[, count]),替换次数)
pattern = re.compile(r'(\w+) (\w+)')
s = 'i say,hello world!'
print(re.subn(pattern,r'\2 \1',s))
def func(m):
return m.group(1).title()+" "+m.group(2).title()
print(re.subn(pattern,func,s))
('say i,world hello!', 2)
('I Say,Hello World!', 2)
python Re 模块的另一种使用方式
re模块中的方法的使用一般将pattern作为第一个参数传入,例如re.match(pattern),还有一种使用方式,即pattern.match()