Python基础之正则表达式

正则表达式是一个特殊的字符序列,它常常用于检查是否与某种模式匹配。从以下几方面介绍Python正则表达式的用法。

re模块的使用

match(正则表达式,待匹配字符串)

用于正则匹配检查,如果待匹配字符串能够匹配正则表达式,则match方法返回匹配对象,否则返回None

import re #导入re模块

#从起始位置开始匹配
rs = re.match("chinahadoop", "chinahadoop.cn") 
print(rs.group())
#不从起始位置开始匹配
rs = re.match("cn", "chinahadoop.cn")

采用从左往右逐项比较匹配,从起始位置起

group()方法

用来返回字符串的匹配部门

字符匹配

单字符匹配:

字符 描述
. 匹配除"\n"之外的任意一个字符
\d 匹配0到9之间的一个数字,它和[0-9]是等价的
\D 匹配一个非数字字符,和[^0-9]是等价的
\s 匹配任意空白字符,包括:空格,\t,\n,\x0B,\f,\r
\S 匹配任意非空白字符
\w 匹配任意单词字符,包括下划线和数字,如a-z的小写字符,A-Z的大写字符,0-9,_
\W 匹配任意非单词字符 ,等价于[^a-zA-Z0-9_]
[] 匹配[]中列举的字符
^ 取反
  • . 匹配除”\n”之外的任意单个字符
import re

rs = re.match(".", "a")
print(rs.group())

rs = re.match("...", "abc")    #多个字符
print(rs.group())

rs = re.match(".", "\n")
print(rs)
  • \s:匹配任意空白字符,如空格,制表符“\t”,换行符“\n”
import re

rs = re.match("\s", "\t")
print(rs)
rs = re.match("\s", "\n")
print(rs)
rs = re.match("\s", " ")
print(rs)
  • \S:匹配任意非空字符;和\s模式相反
rs = re.match("\S", "\t")
print(rs)
rs = re.match("\S", "abc")  #匹配单个字符,从起始位置
print(rs.group())
  • []: 匹配[ ]中列举的字符
rs = re.match("[Hh]", "hello")
print(rs.group())
rs = re.match("[Hh]", "Hello")
print(rs.group())
rs = re.match("[0123456789]", "32")
print(rs.group())
rs = re.match("[0-9]", "3")
print(rs.group())

数量表示

数量表示方法:

字符 描述
* 一个字符可以出现任意次,也可以一次都不出现
+ 一个字符至少出现一次
一个字符至多出现一次
{m} 一个字符出现m次
{m,} 一个字符至少出现m次
{m,n} 一个字符出现m到n次
    • 出现次数 n >= 0
import re

rs = re.match("1\d*", "1234567")     #起始是1,后面数字[0-9]出现任意次
print(rs.group())

rs = re.match("1\d*", "1234567abc")     #起始是1,后面数字[0-9]出现任意次
print(rs.group())
    • 出现次数n >=1
rs = re.match("\d+", "abc")
print(rs)

rs = re.match("\d+", "1abc")
print(rs.group())
  • {m}, {m,} 和 {m, n}
#{m} : 一个字符出现m次
rs = re.match("\d{3}", "123abc")
print(rs.group())

#{m,} :一个字符至少出现m次
rs = re.match("\d{1,}", "123467abc")      #等价于+至少一次
print(rs.group())

#{m,n} :一个字符出现m到n次
rs = re.match("\d{0,1}", "1abc")             #等价于?至多一次
print(rs.group())
  • \转义字符
str1 = "hello\\world"
print(str1)
str2 = "hello\\\\world"
print(str2)
str3 = r"hello\\world"       #原生字符:r"str"
print(str3)
rs = re.match("\w{5}\\\\\\\\\w{5}",str3)
print(rs.group())

rs = re.match(r"\w{5}\\\\\w{5}",str3)
print(rs.group())

边界表示

字符串与单词边界:

字符 描述
^ 用于匹配一个字符串的开头
$ 用于匹配一个字符串的结尾
\b 用于匹配单词的边界
\B 用于匹配非单词边界

应用场景:是否要加边界,区别:比如用户注册的时候验证他输入的邮箱就要加边界,限制他写入的是合法的邮箱,再比如处理文本数据的时候提取邮箱信息,有可能文本里的数据就是非法的,只是为了提取出邮箱,就不用加边界。

  • 字符串与单词边界:$结尾
#边界表示
# $字符串结尾
import re

rs = re.match('1[3578]\d{9}$','13623456767')
print(rs.group())

rs = re.match('1[3578]\d{9}$','13623456767abc')
print(rs)

rs = re.match("\w{3,10}@163.com","hello_124@163mcom")
print(rs.group())

rs = re.match("\w{3,10}@163\.com$","hello_124@163.com")
print(rs.group())

注意:第一个邮箱匹配实际是我们不期望的。但是它仍然被匹配成功,是因为字符. 被当成单字符匹配了。所以我们需要加上转义字符,让. 被当成正常字符。

匹配分组:

字符 描述
() 将括号中字符作为一个分组
\NUM 配合分组()使用,引用分组NUM(NUM表示分组的编号)对应的匹配规则
(?P=name) 应用指定别名的分组匹配到的字符串
html_str = "<title>python</title>"
rs = re.match(r"<.+><.+>.+<!--.+--><!--.+-->",html_str)
print(rs.group())

html_str2 = "<title>python</head></title>"
rs = re.match(r"<.+><.+>.+<!--.+--><!--.+-->",html_str2)   #wrong to match
print(rs.group())

rs = re.match(r"<(.+)><(.+)>.+<!--\2--><!--\1-->",html_str)   #\2 and \1 is an index
print(rs.group())

rs = re.match(r"<(?P<g1>.+)><(?P<g2>.+)>.+<!--(?P=g2)--><!--(?P=g1)-->",html_str)
print(rs.group())

正则表达式的高级用法

search:从左到右在字符串的任意位置搜索第一次出现匹配给定正则表达式的字符

findall:在字符串中查找所有匹配成功的组,返回匹配成功的结果列表

finditer:在字符串中查找所有正则表达式匹配成功的字符串,返回iterator迭代器

sub:将匹配到的数据使用新的数据替换

split:根据指切定的分隔符切割字符串,返回切割之后的列表

#search
rs = re.search("car","haha car carbal abcar carbal")
print(rs.group())


#findall : return a list
rs = re.findall("car","haha car carbal abcar carbal")
print(rs)
mail_str = "zhangsan:helloworld@163.com,li:123456@qq.cn"
list = re.findall(r"(\w{3,20}@(163|qq)\.(com|cn))",mail_str)
print(list)


#finditer
itor = re.finditer(r"\w{3,20}@(163|qq)\.(com|cn)",mail_str)
for it in itor:
    print(it.group())


#sub :java 被python替换。sub()方法的第二个参数还可以是一个函数。
str = "java python c cpp java"
rs = re.sub(r"java","python",str)
print(rs)

贪婪与非贪婪模式

rs = re.findall(r"hello\d*","hello12345")
print(rs)


rs = re.findall(r"hello\d*?","hello12345")
print(rs)

贪婪模式

正则表达式引擎默认是贪婪模式,尽可能多的匹配字符

import re

#贪婪模式
rs = re.findall(r'hello\d*','hello12345')
print(rs)

rs = re.findall(r'hello\d+','hello12345') #至少出现一次
print(rs)

rs = re.findall(r'hello\d?','hello12345') #至多出现一次
print(rs) 

rs = re.findall(r'hello\d{2,}','hello12345') #至少2次以上
print(rs) 

rs = re.findall(r'hello\d{1,3}','hello12345') #1-3次
print(rs) 

非贪婪模式

与贪婪模式相反,尽可能少的匹配字符
在表示数量的"*","?","+","{m,n}"符号后面加上?,使贪婪变成非贪婪。

import re
#非贪婪模式
rs = re.findall(r'hello\d*?','hello12345')
print(rs)

rs = re.findall(r'hello\d+?','hello12345') #至少出现一次
print(rs)

rs = re.findall(r'hello\d??','hello12345') #至多出现一次
print(rs) 

rs = re.findall(r'hello\d{2,}?','hello12345') #至少2次以上
print(rs) 

rs = re.findall(r'hello\d{1,3}?','hello12345') #1-3次
print(rs)