python3 正则表达式入门

写爬虫,怎么可以不会正则呢?

Python大本营?8月19日

作者 | 丹枫无迹?

来源 | 大龄码农的Python之路(ID:gl-1573)

导读:正则在各语言中的使用是有差异的,本文以 Python 3 为基础。本文主要讲述的是正则的语法,对于 re 模块不做过多描述,只会对一些特殊地方做提示。

很多人觉得正则很难,在我看来,这些人一定是没有用心。其实正则很简单,根据二八原则,我们只需要懂 20% 的内容就可以解决 80% 的问题了。我曾经有几年几乎每天都跟正则打交道,刚接手项目的时候我对正则也是一无所知,花半小时百度了一下,然后写了几个 demo,就开始正式接手了。三年多时间,我用到的正则鲜有超出我最初半小时百度到的知识的。

1、正则基础

1.1、基础语法

(1)常用元字符

(2)限定词(又叫量词)

(3)常用反义词

(4)字符族

以上便是正则的基础内容,下面来写两个例子看下:

s?='123abc你好'

re.search('\d+',?s).group()

re.search('\w+',?s).group()

结果:

123

123abc你好

是不是很简单?

1.2、修饰符

修饰符在各语言中也是有差异的。

Python 中的修饰符:

(1)re.A

修饰符?A?使?\w?只匹配 ASCII 字符,\W?匹配非 ASCII 字符。

s?='123abc你好'

re.search('\w+',?s,?re.A).group()

re.search('\W+',?s,?re.A).group()

结果:

123abc

你好

但是描述中还有?\d?和?\D,数字不都是 ASCII 字符吗?这是什么意思?别忘了,还有全角和半角!

s?='0123456789'#?全角数字

re.search('\d+',?s,?re.U).group()

结果:

0123456789

(2)re.M

多行匹配的模式其实也不常用,很少有一行行规整的数据。

s='aaa\r\nbbb\r\nccc'

re.findall('^[\s\w]*?$',?s)

re.findall('^[\s\w]*?$',?s,?re.M)

结果:

['aaa\r\nbbb\r\nccc']#?单行模式

['aaa\r','bbb\r','ccc']#?多行模式

(3)re.S

这个简单,直接看个例子。

s='aaa\r\nbbb\r\nccc'

re.findall('^.*',?s)

re.findall('^.*',?s,?re.S)

结果:

['aaa\r']

['aaa\r\nbbb\r\nccc']

(4)re.X

用法如下:

rc?=?re.compile(r"""

\d+?#?匹配数字

#?和字母

[a-zA-Z]+

"""

,?re.X)

rc.search('123abc').group()

结果:

123abc

注意,用了X修饰符后,正则中的所有空格会被忽略,包括正则里面的原本有用的空格。如果正则中有需要使用空格,只能用\s代替。

(5)(?aiLmsux)

修饰符不仅可以代码中指定,也可以在正则中指定。(?aiLmsux)?表示了以上所有的修饰符,具体用的时候需要哪个就在 ? 后面加上对应的字母,示例如下,(?a)?和?re.A?效果是一样的:

s?='123abc你好'

re.search('(?a)\w+',?s).group()

re.search('\w+',?s,?re.A).group()

结果是一样的:

123abc

123abc

1.3、贪婪与懒惰

当正则表达式中包含能接受重复的限定符时,通常的行为是(在使整个表达式能得到匹配的前提下)匹配尽可能多的字符。

s?='aabab'

re.search('a.*b',?s).group()#?这就是贪婪

re.search('a.*?b',?s).group()#?这就是懒惰

结果:

aabab

aab

简单来说:

所谓贪婪,就是尽可能的匹配;

所谓懒惰,就是尽可能的匹配。

*、+、{n,}?这些表达式属于贪婪;

*?、+?、{n,}??这些表达式就是懒惰(在贪婪的基础上加上??)。

2、正则进阶

2.1、捕获分组

注意:在其他语言或者网上的一些正则工具中,分组命名的语法是?(?<name>exp)或(?'name'exp),但在 Python 里,这样写会报错:This named group syntax is not supported in this regex dialect。Python 中正确的写法是:(?P<name>exp)

示例一:

分组可以让我们用一条正则提取出多个信息,例如:

s =?'姓名:张三;性别:男;电话:138123456789'

m?=?re.search('姓名[::](\w+).*?电话[::](\d{11})',?s)

if?m:

name?=?m.group(1)

phone?=?m.group(2)

print(f'name:{name},?phone:{phone}')

结果:

name:张三,phone:13812345678

示例二:

(?P<name>exp)?有时还是会用到的,?(?P=name)?则很少情况下会用到。我想了一个?(?P=name)?的使用示例,给大家看下效果:

s?='''

张三

30

138123456789

'''

pattern?=r'<(?P<name>.*?)>(.*?)</(?P=name)>'

It?=?re.findall(pattern,?s)

结果:

[('name',?'张三'),?('age',?'30'),?('phone',?'138123456789')]

2.2、零宽断言

注意:正则中常用的前项界定(?<=exp)和前项否定界定(?<!exp)在 Python 中可能会报错:look-behind requires fixed-width pattern,原因是 python 中前项界定的表达式必须是定长的,看如下示例:

(?<=aaa)#?正确

(?<=aaa|bbb)#?正确

(?<=aaa|bb)#?错误

(?<=\d+)#?错误

(?<=\d{3})#?正确

2.3、条件匹配

这大概是最复杂的正则表达式了。语法如下:

此语法极少用到,印象中只用过一次。

以下示例的要求是:如果以 _ 开头,则以字母结尾,否则以数字结尾。

s1?='_abcd'

s2?='abc1'

pattern?='(_)?[a-zA-Z]+(?(1)[a-zA-Z]|\d)'

re.search(pattern,?s1).group()

re.search(pattern,?s2).group()

结果:

_abcd

abc1

2.4、findall

Python 中的?re.findall?是个比较特别的方法(之所以说它特别,是跟我常用的 C# 做比较,在没看注释之前我想当然的掉坑里去了)。我们看这个方法的官方注释:

Returna?listofall?non-overlapping?matchesinthestring.

Ifoneormore?capturing?groups?are?presentinthe?pattern,return

a?listofgroups;?this?will?be?a?listoftuplesifthe?pattern

has?more?than?onegroup.

Empty?matches?are?includedinthe?result.

简单来说,就是

如果没有分组,则返回整条正则匹配结果的列表;

如果有 1 个分组,则返回分组匹配到的结果的列表;

如果有多个分组,则返回分组匹配到的结果的元组的列表。

看下面的例子:

s='aaa123bbb456ccc'

re.findall('[a-z]+\d+',?s)#?不包含分组

re.findall('[a-z]+(\d+)',?s)#?包含一个分组

re.findall('([a-z]+(\d+))',?s)#?包含多个分组

re.findall('(?:[a-z]+(\d+))',?s)#??:?不捕获分组匹配结果

结果:

['aaa123',?'bbb456']

['123',?'456']

[('aaa123',?'123'),?('bbb456',?'456')]

['123',?'456']

零宽断言中讲到 Python 中前项界定必须是定长的,这很不方便,但是配合 findall 有分组时只取分组结果的特性,就可以模拟出非定长前项界定的效果了。

结语

其实正则就像是一个数学公式,会背公式不一定会做题。但其实这公式一点也不难,至少比学校里学的数学简单多了,多练习几次也就会了。


谁偷偷删了你的微信?别慌!Python帮你都揪出来了

吐血整理!140种Python标准库、第三方库和外部工具都有了

如何用爬虫技术帮助孩子秒到心仪的幼儿园(基础篇)

Python传奇:30年崛起之路

?著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,100评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,308评论 3 388
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事?!?“怎么了?”我有些...
    开封第一讲书人阅读 159,718评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,275评论 1 287
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,376评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,454评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,464评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,248评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,686评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,974评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,150评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,817评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,484评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,140评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,374评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,012评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,041评论 2 351

推荐阅读更多精彩内容

  • Python中的正则表达式(re) import rere.match #从开始位置开始匹配,如果开头没有则无re...
    BigJeffWang阅读 7,070评论 0 99
  • 一、正则表达式语法 正则表达式是用匹配或者描述字符串的工具。 用处:a.判断字符串是否满足某个条件---判断输入的...
    大漠判官1阅读 353评论 0 1
  • #首先,python中的正则表达式大致分为以下几部分: 元字符 模式 函数 re 内置对象用法 分组用法 环视用法...
    mapuboy阅读 1,605评论 0 51
  • 1.付出不亚于任何人的努力 2.要谦虚,不要骄傲 3.要每天反省 4.活着,就要感谢 5.积善行,思利他 6.不要...
    六项精进阿晋阅读 184评论 0 0
  • 这些文章的起源都是来自于一位集美丽与特别的川妹子组织写作活动而来。 车,基本上是男人说喜欢谈的话题。也是男人喜欢的...
    SELFDISCIPLINEH阅读 215评论 2 1