秀!这应该是最好的 “re正则表达式” 使用教程了

这是「进击的Coder」的第 379 篇技术分享
作者:黄伟呢
来源:数据分析与统计学之美

阅读本文大概需要 3 分钟。



其实写正则表达式的人,挺多的。但还是有朋友让黄同学再写一遍,那行吧,黄同学笔记早就有了,只不过感觉别人写的都很全了,不好意思班门弄斧。
既然在写一次,我是想写的精简一些,挑重点的讲。
秀!这应该是最好的 “re正则表达式” 使用教程了

1. 什么是“正则表达式”

“正则表达式” 是一组由字母和符号组成的特殊文本,可以帮助我们从某个复杂的字符串中,提取出满足我们要求的特殊文本。
用一个我理解的比喻带着大家体会 “正则匹配的过程”。苹果道具相当于写的“正则表达式”,水果市场相当于“字符串”,“正则匹配的过程”就相当于拿着苹果道具去“水果市场”找苹果的过程,每匹配到一个就返回一个,否则就什么也没有。

2. 常用“操作符”介绍

正则表达式之所以这么强大,是因为拥有很多专用的操作符(又称“元字符”)、特殊字符修饰符
所谓“元字符”,指的是那些不仅仅可以表示字符本身含义、并且还可以表示其他特殊含义的字符。常用的元字符有. [ ] () ^ $ | ? * +{ }共11种,为了更加方便记忆和学习正则表达式,我将元字符再细化为 7 个普通元字符 + 4 个常用量化符
特殊字符主要介绍了 6 个,d、 D、 s、 S、 w、 W
修饰符主要介绍 3 个,re.I、re.M、re.S
① 7 个普通元字符
下面这 7 个符号,我相信并不太多,大家一定可以记忆下来,不行就设置为壁纸帮助记忆。黄同学真的是一分再分,只能简化这份上了。
秀!这应该是最好的 “re正则表达式” 使用教程了
② 4 个常用量化符
所为“量化符”,指的就是将紧挨着量化符前面的那个字符,匹配 0 次、1 次或者多次,详细说明见下表。
秀!这应该是最好的 “re正则表达式” 使用教程了
③ 6 个特殊符号
所为“特殊符”,指的就是由转义字符加某些字母组合而成的,具有特殊意义的特殊字符,详细说明见下表。
秀!这应该是最好的 “re正则表达式” 使用教程了
④ 3 个常用修饰符
其实正则表达式中的修饰符不止 3 个,但是我只挑重要的给大家讲,详细说明见下表。
秀!这应该是最好的 “re正则表达式” 使用教程了

3. 常用方法介绍

其中三个函数用于查找匹配 match()search()findall(),一个函数 sub() 用于替换,一个函数 split() 用于切分字符串,还有一个函数 compile() 用于编译正则表达式。
在分别讲述这些函数之前,我们分别讲述一下这些函数的含义。
  • match():匹配字符串的开头,如果开头匹配不上,则返回 None;
  • search():扫描整个字符串,匹配后立即返回,不在往后面匹配;
  • findall():扫描整个字符串,以列表形式返回所有的匹配值;
  • compile():将字符串编译成正则表达式对象,供 match() 、 search() 和findall() 函数使用;
  • sub():扫描整个字符串,用于替换字符串的某些值;
  • split():扫描整个字符串,按照指定分隔符切分字符串;
① match(pattern,string,flag)
match() 函数语法格式如下:
  • pattern:你写的正则表达式;
  • string:待匹配的字符串;
  • flag:修饰符;
首先咱们来演示 match() 函数的用法。对于这样一个字符串 s1:
s1 = 'ab黄cd同abc学'
需求一:我们想要得到字符串 s1 中的 a,使用 match() 函数应该怎么做。
re.match('a',s1)
结果如下:
秀!这应该是最好的 “re正则表达式” 使用教程了
可以发现:这里得到的是一个match对象,并没有任何的结果。那么,怎么获取到具体的值。
直接调用对象的 group() 函数,可以获取到具体的值。
s1 = 'ab黄cd同abc学'
r1 = re.match('a',s1)
r1.group()
结果如下:
秀!这应该是最好的 “re正则表达式” 使用教程了
可以发现,match() 函数一旦匹配到具体值,就立即返回,不再往后面匹配。因此,这里只返回了一个 'a'。
需求二:我们现在不想匹配字符串 s1 中的 a,而是想匹配 s1 中的 b,又应该怎么做呢?
s1 = 'ab黄cd同abc学'
r2 = re.match('b',s1)
r2.group()
结果如下:
秀!这应该是最好的 “re正则表达式” 使用教程了
此时可以发现:报错了。这是由于 match() 函数只能从字符串开头匹配,如果开头没有匹配上,则会报错。因为字符串 s1 是以 a 开头,不是以 b 开头,所以匹配不上。
注:这个函数局限性太大,用的不是太多,因此大家知道这个事儿就行。match() 函数主要是用于区分下面要讲的 search() 函数。
② search(pattern, string,flag)
search() 函数语法格式如下:
  • pattern:你写的正则表达式;
  • string:待匹配的字符串;
  • flag:修饰符;
还是同样的一个字符串 s1:
s1 = 'ab黄cd同abc学'
需求一:我们想要得到字符串 s1 中的 a,使用 search() 函数应该怎么做。
s1 = 'ab黄cd同abc学'
r2 = re.search('a',s1)
r2.group()
结果如下:
秀!这应该是最好的 “re正则表达式” 使用教程了
需求二:使用 search() 函数,去匹配字符串 s1 中的 b。
s1 = 'ab黄cd同abc学'
r2 = re.search('b',s1)
r2.group()
结果如下:
秀!这应该是最好的 “re正则表达式” 使用教程了
search() 函数与 match() 函数不同点:match() 函数如果开头匹配不上,就无法匹配。search() 函数是扫描整个字符串,只要能匹配上,就有结果。
search() 函数与 match() 函数相同点:它们一旦匹配上了,就立即返回结果,而不再往后面匹配(即使后面能匹配上)。如果都匹配不上,会出现同样的错误,如下图所示:
秀!这应该是最好的 “re正则表达式” 使用教程了
注意:search() 函数比 match() 函数要实用一些,有时候我们只想匹配字符串的,第一个匹配值,后面的匹配值我们不想要,search() 函数可以很好的帮忙。
③ findall(pattern, repl, string, count=0, flags=0)
findall() 函数语法格式如下:
  • pattern:你写的正则表达式;
  • string:待匹配的字符串;
  • flag:修饰符;
findall() 函数,不管是我们做爬虫,还是我们做数据清洗,都属于高频函数,大家一定要好好掌握。
我们先看一个简单的例子:
还是前面的字符串 s1,我们分别只想获取 a、只想获取 b、获取 a 或 b,使用 findall() 会出现什么结果呢?
s1 = 'ab黄cd同abc学'
re.findall('a',s1)

re.findall('b',s1)

re.findall('[a | b]',s1)
结果如下:
秀!这应该是最好的 “re正则表达式” 使用教程了
可以发现:finadll() 函数会直接返回所有匹配对象,组成的列表(记住:返回的是列表),不像 search() 函数与 match() 函数,还需要调用 group() 函数,这个大家一定要注意。
如果 finadll() 函数,没有匹配上,不会报错,而是返回一个空列表。
s1 = 'ab黄cd同abc学'
re.findall('f',s1)
结果如下:
秀!这应该是最好的 “re正则表达式” 使用教程了
我们在来看一个稍微复杂一点的案例(爬虫经常见到的)
html = '''<html>
<head lang="en">
<title>Title</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>
<body>
   <div id="content">
       <ul id="ul1">
           <li>first</li>
           <li>second</li>
           <li>third</li>
       </ul>
       <ul id="ul2">
           <li>alpha</li>
           <li>beta</li>
       </ul>
    </div>
    <div id="url">
        <a href="http:www.baidu.com" title="baidu">baidu</a>
        <a href="http:www.tipdm.com" title="tipdm">tipdm</a>
    </div>
</body>
</html>
'''
如果我们想要使用正则表达式,获取其中的 li 标签,或者获取其中的 href 属性,应该怎么做呢?
# 获取li标签
re.findall('<li>(.*?)</li>',html)

# 获取href属性
re.findall('<a href="(.*?)" ',html)
结果如下:
秀!这应该是最好的 “re正则表达式” 使用教程了
操作其实很简单,固定写法:首尾照抄字符串源代码,我们想要的东西使用 () 小括号,括起来,里面写上 .*?
上面提到了一个 .* 与 .*?,其中 .* 表示贪婪匹配,.*? 表示非贪婪匹配。
  • . 可以匹配除了换行符以外的所有字符;
  • * 表示匹配前面的字符无限次;
  • ? 前面紧挨的元素,最多匹配一次;
我们用一个例子简单说明:
s2 = 'a123b456b789b3'
re.findall('a(.*)3',s2)
re.findall('a(.*?)3',s2)
结果如下:
秀!这应该是最好的 “re正则表达式” 使用教程了
用一句通俗的话说明它们的区别:贪婪匹配是尽可能多的匹配内容,非贪婪匹配是尽可能少的 匹配内容。字符串 s2 中有两个 3,贪婪匹配会一直匹配到最后一个 3,但是非贪婪匹配找到第一个 3 后,就停止了。
④ compile()
compile 函数将字符串编译成正则表达式对象,供 match() 、 search() 和 findall() 函数使用。
即:先定义一个正则表达式对象 (Pattern对象),然后分别调用该对象的 match() 、 search() 和 findall() 函数,这三个函数用法与它们原本用法相同。
我们直接用一个例子讲述该函数:
type(re.compile(r'd+')) 
结果如下:
秀!这应该是最好的 “re正则表达式” 使用教程了
可以看到这是一个 Pattern 对象。
s3 = '12one34two56three78four'
# 定义一个正则表达式对象,用于匹配至少一个数字
pattern = re.compile(r'd+'
# 扫描整个字符串,匹配s3字符串中,符合该正则表达式的字符串。(这里调用的是对象的findll()对象)。
pattern.findall(s3)
# 从s3字符串,下标为1的位置,查找匹配值。
pattern.findall(s3,1)
# 从s3字符串,下标为1到下标为6的位置之间,查找匹配值。
pattern.findall(s3,1,6)
结果如下:
秀!这应该是最好的 “re正则表达式” 使用教程了
⑤ sub(pattern, repl, string, count, flags)
sub() 函数是 Python 正则表达式中,专门用于“替换”的函数。
sub() 函数语法格式如下:
  • pattern:你写的正则表达式;
  • repl:替换成啥;
  • string:待替换的字符串;
  • count:表示最大替换次数,默认 0 表示替换所有的匹配;
  • flag:修饰符;
同样对于上述提到的字符串 s3,我们将“英文字母” 全部替换为 “字母”两个字,应该做么办呢?
# 'D{3,5}'表示匹配非数字3-5次。
s3 = '12one34two56three78four'
# 这里没有指定最大匹配次数,因此默认会替换所有的匹配值
re.sub('D{3,5}','字母',s3)
# 这里指定最大匹配次数count=2,因此只会替换前2个匹配值
re.sub('D{3,5}','字母',s3,2)
# 如果count=3,则会替换3个匹配值
re.sub('D{3,5}','字母',s3,3)
结果如下:
秀!这应该是最好的 “re正则表达式” 使用教程了
⑥ split(pattern, string, maxsplit, flags)
split() 函数是 Python 正则表达式中,专门用于“切分字符串”的函数。
split() 函数语法格式如下:
  • pattern:你写的正则表达式;
  • string:待分割的字符串;
  • maxsplit:最大分割次数,默认为 0,表示不限制分割次数;
  • flag:修饰符;
有这样一个字符串 s4,我们以“-”为分隔符切分字符串,看看使用 split() 函数会得到什么样的结果。
# 'D'表示匹配非数字
s4 = '136-3456-7413'
# 这里如果不指定“最大分割次数”,则是不限次数切分
re.split('D',s4)
# 如果指定最大分割次数maxsplit=1,那么就只以第一个分隔符,进行切分
re.split('D',s4,1)
结果如下:
秀!这应该是最好的 “re正则表达式” 使用教程了
限于篇幅!这篇文章就讲述到这里啦,感谢你的阅读。
秀!这应该是最好的 “re正则表达式” 使用教程了

End

「进击的Coder」专属学习群已正式成立,搜索「CQCcqc4」添加崔庆才的个人微信或者扫描下方二维码拉您入群交流学习。


秀!这应该是最好的 “re正则表达式” 使用教程了

看完记得关注@进击的Coder
及时收看更多好文
↓↓↓


赶紧动手试一试


原文始发于微信公众号(进击的Coder):秀!这应该是最好的 “re正则表达式” 使用教程了

本站文章资源均来源自网络,除非特别声明,否则均不代表站方观点,并仅供查阅,不作为任何参考依据!
如有侵权请及时跟我们联系,本站将及时删除!
如遇版权问题,请查看 本站版权声明
THE END
分享
二维码
海报
秀!这应该是最好的 “re正则表达式” 使用教程了
这是「进击的Coder」的第 379 篇技术分享 作者:黄伟呢 来源:数据分析与统计学之美 “ 阅读本文大概需要 3 分钟。 ” 其实写正则表达式的人,……
<<上一篇
下一篇>>