美文网首页
正则表达式初探

正则表达式初探

作者: SimonJoe246 | 来源:发表于2018-12-07 22:09 被阅读0次

正则表达式

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

这时,我们可以

  • 创建一个正则表达式

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

正则表达式(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')

相关文章

网友评论

      本文标题:正则表达式初探

      本文链接:https://www.haomeiwen.com/subject/zazxhqtx.html