正则表达式初探

正则表达式

字符串是编程时遇到的最多的一种数据结构,比如判断一个电子邮件地址或一个座机号码是否符合格式要求,虽然我们可以提取 @ 前后的字符串,再分别判断单词和域名,但这样代码十分复杂, 而且难以复用。

这时,我们可以

  • 创建一个正则表达式

  • 用这个正则表达式去检测字符串是否合法

正则表达式(Regulation Expression)是一种文本模式,包括普通字符(例如,a 到 z之间的字母,数字)和特殊字符(称为元字符,具有图书意义的字符,如 +表示其前导字符至少出现1次,$*()

基本用法

正则表达式本身也是个字符串,怎么用字符描述字符呢?这就是我们这篇文章要讲的主要内容。

直接给出字符,就是精确匹配:

\d 表示一个数字

\w 表示一个字母或数字

. 表示任意字符,若要表示 . 英文句号,需要加转义字符 \.

因此:

00\d 可以匹配 003004,但无法匹配 00A

\w\w\w 可以匹配 010

py. 可以匹配 pyapy3py!

怎么匹配变长字符串:

  • * 表示任意个字符(包括0个),如 runoo*b 可以匹配 runobrunoobrunooob

  • + 表示至少出现一次

  • ? 表示出现 0 次或 1 次

  • {n,m} 表示 n-m 个字符,注意:两个数字 n 和 m 之间不能有空格,只用逗号分隔

所以,\d{3}\s+\d{3,8} 可以匹配任意用空格隔开的带区号的电话号码

但是,以上方法匹配 010 - 2569888 还是不可以的,需要正则的高级用法

进阶

当有多种类型字符选择时,如数字、字母、大小写,可以用 [] 来将其包括进去

  • [0-9a-zA-Z\_] 可以匹配一个数字、字母、下划线

  • [0-9a-zA-Z\_]+ 可以匹配至少由一个数字、字母、下划线组成的字符串,如0558python343

  • [a-zA-Z\_][0-9a-zA-Z\_]* 可以匹配由字母或下划线开头的字符串,也是 python 合法变量格式

  • [a-zA-Z\_][0-9a-zA-Z\_]{1,19} 可以精确限制了字符串的长度是 1-20

  • A|B 匹配 AB,所以 (P|p)ython 可以匹配 pythonPython

  • ^表示行的开头,^\d表示以数字开头

  • $表示行尾,\w$ 表示以字母结尾

^$有什么作用,py 是可以匹配 python的,但 ^py$ 就只能匹配 py

python的 re 模块

python 内置了 re 正则模块,

现在尝试写一个正则表达式以验证 Email 地址:

Email 地址格式要求:

name@domain

name最长64,domain最长253,总长最长256

name可以使用任意ASCII字符:

  • 大小写英文字母 a-z,A-Z

  • 数字 0-9

  • 字符 !#$%&'*+-/=?^_`{|}~

  • 字符 .不能是第一个和最后一个,不能连续出现两次

但是有些邮件服务器会拒绝包含有特殊字符的邮件地址

domain仅限于26个英文字母、10个数字、连词号-

连词号-不能是第一个字符

顶级域名(com、cn等)长度为2到6个

代码如下:

>>> r = r'^[a-zA-Z]+[\.\_]?[a-zA-Z0-9]+@[a-zA-Z0-9]([\_]?[a-zA-Z0-9]+)*\.[a-zA-Z]{2,6}(\.[a-zA-Z]{2})?$'
>>> re.match(r, 'simonkindle@126.com')
<_sre.SRE_Match object; span=(0, 19), match='simonkindle@126.com'>
>>> re.match(r, 'simonkindle@126.com.cn')
<_sre.SRE_Match object; span=(0, 22), match='simonkindle@126.com.cn'>
>>> re.match(r, 'simonkindle@126.com.cn.cn')

贪婪匹配

*+ 都是贪婪匹配的,即在符合格式要求的情况下尽可能多地匹配文字。如果想取消贪婪匹配,在它们后面加上一个 ? 即可。

具体看下面例子:

>>> todo = `<H1>Chapter 1 - 介绍正则表达式</H1>`
>>> r = '<.*>'
>>> re.match(r, todo)
<_sre.SRE_Match object; span=(0, 28), match='<H1>Chapter 1 - 介绍正则表达式</H1>'>
>>> r = '<.*?>'
>>> re.match(r, todo)
<_sre.SRE_Match object; span=(0, 4), match='<H1>'>

前者贪婪匹配,匹配 <> 之间尽可能多的字符,后者非贪婪匹配,匹配 <> 之间尽可能少的字符。

切分字符串

正则表达式还可以用来切分字符串,如何将以不定数空格分割的单词提取出来?

>>> s = 'a  b fef   v'
>>> s.split(' ')
['a', '', 'b', 'fef', '', '', 'v']

无法识别连续空格

>>> r = '[\s]+'
>>> re.split(r, s)
['a', 'b', 'fef', 'v']

分组

正则表达式还有提取子字符串的功能。用 () 表示的就是要提取的分组(Group)。

>>> r = '^(\d{3})-(\d{3,8})$'
>>> m = re.match(r, '022-22820279')
>>> m.groups()
('010', '22820279')
>>> m[0]
'010-22820279'
>>> m[1]
'010'
>>> m[2]
'22820279'
>>> m[3]

group(0)永远是原字符串,之后依次是括号中的字串

编译

当我们在 python 中使用正则表达式时,re 模块会在背后干这样两件事:

  • 编译正则表达式,如果字符串本身不合法,会报错

  • 用编译后的正则表达式去匹配字符串

如果我们使用的正则表达式要匹配上千次,每次都要编译会浪费大量时间。出于效率考虑,我们可以预编译该表达式,这样以后匹配就省去这个步骤了

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

推荐阅读更多精彩内容

  • Python中的正则表达式(re) import rere.match #从开始位置开始匹配,如果开头没有则无re...
    BigJeffWang阅读 7,077评论 0 99
  • python的re模块--细说正则表达式 可能是东半球最详细最全面的re教程,翻译自官方文档,因为官方文档写的是真...
    立而人阅读 22,873评论 4 46
  • 我希望,我十年后可以变成一名老师。我可以当上一名舞蹈老师,作文老师,数学老师,语文老师,英语老师,健美操老...
    薛乔丹阅读 551评论 0 0
  • 我从不是一个意志坚定的人,很容易受环境影响。初三时,晚自习后回到家,几乎每日都会一个人对着墙壁发呆,时常有天马行空...
    冷雨淋门阅读 185评论 0 0
  • 嗨 今天晚上的星星很少 楼顶的风格外清凉 空气中弥漫着雨后的清新 黑夜很漫长 星辰很璀璨 我想跟你说声晚安 有人说...
    拜星月慢阅读 236评论 3 2