正则表达式

正则表达式

正则表达式简介

正则表达式,是一个特殊的字符序列,又称规则表达式(英语:Regular Expression,在代码中常简写为regex、regexp 或RE),本质而言是一种小型的,高度专业化的编程语言。
Python 自1.5版本起增加了re 模块,re 模块使Python语言拥有全部的正则表达式功能。

正则语法表

这个你背不过,再好的教程看了也没用。如何巧记?我们需要对其进行分类。

  • 开头结尾

这一对标签,大家都不会陌生…

模式描述
^从整个字符串开头的地方匹配
$从整个字符串的结尾开始匹配
  • 模糊匹配
模式描述
.匹配任意字符,除了换行符
re?重复匹配?号前面0个或1个由前面的正则表达式定义的片段,非贪婪方式
re*重复匹配*号前面0个或多个的表达式。
re+重复匹配+号前面1个或多个的表达式。
a丨b匹配a或b
  • 关于括号
模式描述
{}表示匹配"{}“前边的字符 指定个数为”{}"里边的数值
[]表示一个字符集,它常被用来指定一个字符类别,字符可以单个列出,也可以用“-”号分隔的两个给定字符来表示一个字符区间
()分组 将括号中的内容 当作整体来对待
  • \ 反斜杠的应用
模式描述
\w匹配字母数字及下划线
\W匹配非字母数字及下划线
\s匹配任意空白字符,等价于 [\t\n\r\f].
\S匹配任意非空字符
\d匹配任意数字,等价于 [0-9].
\D匹配任意非数字
\A匹配字符串开始
\Z匹配字符串结束,如果是存在换行,只匹配到换行前的结束字符串。
\z匹配字符串结束
\G匹配最后匹配完成的位置。
\b匹配一个单词边界,也就是指单词和空格间的位置。例如, ‘er\b’ 可以匹配"never" 中的 ‘er’,但不能匹配 “verb” 中的 ‘er’。
\B匹配非单词边界。‘er\B’ 能匹配 “verb” 中的 ‘er’,但不能匹配 “never” 中的 ‘er’。
\n, \t, 等.匹配一个换行符。匹配一个制表符。等
\1…\9匹配第n个分组的内容。
\10匹配第n个分组的内容,如果它经匹配。否则指的是八进制字符码的表达式。
  • 其他
模式描述
(?imx)正则表达式包含三种可选标志:i, m, 或 x 。只影响括号中的区域。
(?-imx)正则表达式关闭 i, m, 或 x 可选标志。只影响括号中的区域。
(?: re)类似 (…), 但是不表示一个组
(?imx: re)在括号中使用i, m, 或 x 可选标志
(?-imx: re)在括号中不使用i, m, 或 x 可选标志
(?#…)注释.
(?= re)前向肯定界定符。如果所含正则表达式,以 … 表示,在当前位置成功匹配时成功,否则失败。但一旦所含表达式已经尝试,匹配引擎根本没有提高;模式的剩余部分还要尝试界定符的右边。
(?! re)前向否定界定符。与肯定界定符相反;当所含表达式不能在字符串当前位置匹配时成功
(?> re)匹配的独立模式,省去回溯。

re模块用法

re.(function)(pattern[, flags])
pattern : 一个字符串形式的正则表达式
flags : 可选,表示匹配模式,比如忽略大小写,多行模式等,具体参数为:

  1. re.I 忽略大小写
  2. re.L 表示特殊字符集 \w, \W, \b, \B, \s, \S 依赖于当前环境
  3. re.M 多行模式
  4. re.S 即为 . 并且包括换行符在内的任意字符(. 不包括换行符)
  5. re.U 表示特殊字符集 \w, \W, \b, \B, \d, \D, \s, \S 依赖于 Unicode 字符属性数据库
  6. re.X 为了增加可读性,忽略空格和 # 后面的注释
  • findall() (即:全部找到,返回的是一个列表)

findall(string[, pos[, endpos]])
参数:

  1. string : 待匹配的字符串。
  2. pos : 可选参数,指定字符串的起始位置,默认为 0。
  3. endpos : 可选参数,指定字符串的结束位置,默认为字符串的长度。
import re
s = 'helloworld hellobeijing'
ret = re.findall('hello\S+',s)
print(ret)
['helloworld', 'hellobeijing']
  • finditer()

和 findall 类似,在字符串中找到正则表达式所匹配的所有子串,并把它们作为一个迭代器返回。
re.finditer(pattern, string, flags=0)
参数:

参数描述
pattern匹配的正则表达式
string要匹配的字符串。
flags标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等
  • search() 与 match()

相同点:

  1. 语法:re.search/match(pattern, string, flags=0)
  2. 函数参数说明:
参数描述
pattern匹配的正则表达式
string要匹配的字符串。
flags标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等
  1. 可以使用group(num) 或 groups() 匹配对象函数来获取匹配表达式。
匹配方法描述
group(num=0)匹配的整个表达式的字符串,group() 可以一次输入多个组号,在这种情况下它将返回一个包含那些组所对应值的元组
groups()返回一个包含所有小组字符串的元组,从 1 到 所含的小组号
start([group])方法用于获取分组匹配的子串在整个字符串中的起始位置(子串第一个字符的索引),参数默认值为 0
end([group])方法用于获取分组匹配的子串在整个字符串中的结束位置(子串最后一个字符的索引+1),参数默认值为 0
span([group])方法返回 (start(group), end(group)
import re
# re.search
ret = re.search('h..','hello hello world')
print(ret) # 输出结果:<_sre.SRE_Match object; span=(0, 3), match='hel'>
ret1 = re.search('h..','hello hello world').group()
print(ret1) # 输出结果:hel 只输出第一个符合条件的结果

# re.match
ret = re.match('asd','asdhskdjfksji')
print(ret) # 输出结果:<_sre.SRE_Match object; span=(0, 3), match='asd'>返回的是一个对象。
ret1 = re.match('asd','asdhskdjfasdksjiasd').group()
print(ret1) # 输出结果:asd 调用.group()方法,只返回匹配的第一个结果。

不同点:

  1. re.match只匹配字符串的开始,如果字符串开始不符合正则表达式,则匹配失败,函数返回None
  2. re.search匹配整个字符串,直到找到一个匹配
# re.search
s = 'helloworld hellobeijing'
ret = re.search('hellob\S+',s)
print(ret)
<re.Match object; span=(11, 23), match='hellobeijing'>

# re.match
s = 'helloworld hellobeijing'
ret = re.match('hellob\S+',s)
print(ret)
None
  • split() 分隔符 对比字符串里边的split方法。

split 方法按照能够匹配的子串将字符串分割后返回列表,它的使用形式如下:

re.split(pattern, string[, maxsplit=0, flags=0])

参数描述
pattern匹配的正则表达式
string要匹配的字符串。
maxsplit分隔次数,maxsplit=1 分隔一次,默认为 0,不限制次数。
flags标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。参见:正则表达式修饰符 - 可选标志
import re
s = 'helloworld hellobeijing'
ret = re.split('hello',s)
print(ret)
['', 'world ', 'beijing']
  • sub() 替换;类似字符串中的replace()方法。

re.sub用于替换字符串中的匹配项。
语法:
re.sub(pattern, repl, string, count=0, flags=0)
参数:

  1. pattern : 正则中的模式字符串。
  2. repl : 替换的字符串,也可为一个函数。
  3. string : 要被查找替换的原始字符串。
  4. count : 模式匹配后替换的最大次数,默认 0 表示替换所有的匹配。
import re
s = 'helloworld hellobeijing'
ret = re.sub('hello','goodbye',s)
print(ret)
goodbyeworld goodbyebeijing
  • compile(strPattern[,flag]): 这个方法是Pattern类的工厂方法,用于将字符串形式的正则表达式编译为Pattern对象

compile 函数用于编译正则表达式,生成一个正则表达式( Pattern )对象,供 match() 和 search() 这两个函数使用。
语法格式为:
re.compile(pattern[, flags])
参数:
pattern : 一个字符串形式的正则表达式

  1. flags : 可选,表示匹配模式,比如忽略大小写,多行模式等,具体参数为:
  2. re.I 忽略大小写
  3. re.L 表示特殊字符集 \w, \W, \b, \B, \s, \S 依赖于当前环境
  4. re.M 多行模式
  5. re.S 即为 . 并且包括换行符在内的任意字符(. 不包括换行符)
  6. re.U 表示特殊字符集 \w, \W, \b, \B, \d, \D, \s, \S 依赖于 Unicode 字符属性数据库
  7. re.X 为了增加可读性,忽略空格和 # 后面的注释
import re
pattern = re.compile('he.{3}')
pattern.match(s)
<re.Match object; span=(0, 5), match='hello'>

正则练习

import re
1 查找第一个匹配串
s = 'i love python very much'
pat = 'python' 
r = re.search(pat,s)
print(r.span()) #(7,13)
2 查找所有1
s = '山东省潍坊市青州第1中学高三1班'
pat = '1'
r = re.finditer(pat,s)
for i in r:
    print(i)

# <re.Match object; span=(9, 10), match='1'>
# <re.Match object; span=(14, 15), match='1'>
3 \d匹配数字[0-9]
s = '一共20行代码运行时间13.59s'
pat = r'\d+' # +表示匹配数字(\d表示数字的通用字符)1次或多次
r = re.findall(pat,s)
print(r)
# ['20', '13', '59']

我们想保留13.59而不是分开,请看4

4 ?表示前一个字符匹配0或1次
s = '一共20行代码运行时间13.59s'
pat = r'\d+\.?\d+' # ?表示匹配小数点(\.)0次或1次
r = re.findall(pat,s)
print(r)
# ['20', '13.59']
5 ^匹配字符串的开头
s = 'This module provides regular expression matching operations similar to those found in Perl'
pat = r'^[emrt]' # 查找以
r = re.findall(pat,s)
print(r)
# [],因为字符串的开头是字符`T`,不在emrt匹配范围内,所以返回为空
6 re.I 忽略大小写
s = 'This module provides regular expression matching operations similar to those found in Perl'
pat = r'^[emrt]' # 查找以
r = re.compile(pat,re.I).search(s)
print(r)
# <re.Match object; span=(0, 1), match='T'> 表明字符串的开头在匹配列表中
7 使用正则提取单词

这是不准确版本,请参看第9个

s = 'This module provides regular expression matching operations similar to those found in Perl'
pat = r'\s[a-zA-Z]+'  
r = re.findall(pat,s)
print(r) #[' module', ' provides', ' regular', ' expression', ' matching', ' operations', ' similar', ' to', ' those', ' found', ' in', ' Perl']
8 只捕获单词,去掉空格

使用()捕获,这是不准确版本,请参看第9个

s = 'This module provides regular expression matching operations similar to those found in Perl'
pat = r'\s([a-zA-Z]+)'  
r = re.findall(pat,s)
print(r) #['module', 'provides', 'regular', 'expression', 'matching', 'operations', 'similar', 'to', 'those', 'found', 'in', 'Perl']
9 补充上第一个单词

上面第8,看到提取单词中未包括第一个单词,使用?表示前面字符出现0次或1次,但是此字符还有表示贪心或非贪心匹配含义,使用时要谨慎。

s = 'This module provides regular expression matching operations similar to those found in Perl'
pat = r'\s?([a-zA-Z]+)'  
r = re.findall(pat,s)
print(r) #['This', 'module', 'provides', 'regular', 'expression', 'matching', 'operations', 'similar', 'to', 'those', 'found', 'in', 'Perl']
10 使用split函数直接分割单词

使用以上方法分割单词,不是简洁的,仅仅为了演示。分割单词最简单还是使用split函数。

s = 'This module provides regular expression matching operations similar to those found in Perl'
pat = r'\s+'  
r = re.split(pat,s)
print(r) # ['This', 'module', 'provides', 'regular', 'expression', 'matching', 'operations', 'similar', 'to', 'those', 'found', 'in', 'Perl']
11 提取以m或t开头的单词,忽略大小写

下面出现的结果不是我们想要的,原因出在 ?上!

s = 'This module provides regular expression matching operations similar to those found in Perl'
pat = r'\s?([mt][a-zA-Z]*)' # 查找以
r = re.findall(pat,s)
print(r) # ['module', 'matching', 'tions', 'milar', 'to', 'those']
12 使用^查找字符串开头的单词

综合11和12得到所有以m或t开头的单词

s = 'This module provides regular expression matching operations similar to those found in Perl'
pat = r'^([mt][a-zA-Z]*)\s' # 查找以
r = re.compile(pat,re.I).findall(s)
print(r) # ['This']
13 先分割,再查找满足要求的单词

使用match表示是否匹配

s = 'This module provides regular expression matching operations similar to those found in Perl'
pat = r'\s+'  
r = re.split(pat,s)
res = [i for i in r if re.match(r'[mMtT]',i)] 
print(res) # ['This', 'module', 'matching', 'to', 'those']
14 贪心匹配

尽可能多的匹配字符

content='<h>ddedadsad</h><div>graph</div>bb<div>math</div>cc'
pat=re.compile(r"<div>(.*)</div>")  #贪婪模式
m=pat.findall(content)
print(m) # ['graph</div>bb<div>math']
15 非贪心匹配

与14相比,仅仅多了一个问号(?),得到结果完全不同。

content='<h>ddedadsad</h><div>graph</div>bb<div>math</div>cc'
pat=re.compile(r"<div>(.*?)</div>")  #贪婪模式
m=pat.findall(content)
print(m) # ['graph', 'math']

与14比较可知,贪心匹配和非贪心匹配的区别,后者是字符串匹配后立即返回,见好就收。

16 含有多种分割符

使用split函数

content = 'graph math,,english;chemistry' # 这种
pat=re.compile(r"[\s\,\;]+")  #贪婪模式
m=pat.split(content)
print(m) # ['graph', 'math', 'english', 'chemistry']
17 替换匹配的子串

sub函数实现对匹配子串的替换

content="hello 12345, hello 456321"    
pat=re.compile(r'\d+') #要替换的部分
m=pat.sub("666",content)
print(m) # hello 666, hello 666
18 爬取百度首页标题
import re
from urllib import request

#爬虫爬取百度首页内容
data=request.urlopen("http://www.baidu.com/").read().decode()

#分析网页,确定正则表达式
pat=r'<title>(.*?)</title>'

result=re.search(pat,data)
print(result) <re.Match object; span=(1358, 1382), match='<title>百度一下,你就知道</title>'>

result.group() # 百度一下,你就知道

19 常用元字符总结复习

. 匹配任意字符  
^ 匹配字符串始位置 
$ 匹配字符串中结束的位置 
* 前面的原子重复0次1次多次 
? 前面的原子重复一次或者0次 
+ 前面的原子重复一次或多次
{n} 前面的原子出现了 n 次
{n,} 前面的原子至少出现 n 次
{n,m} 前面的原子出现次数介于 n-m 之间
( ) 分组,需要输出的部分
20 常用通用字符总结复习
\s  匹配空白字符 
\w  匹配任意字母/数字/下划线 
\W  和小写 w 相反,匹配任意字母/数字/下划线以外的字符
\d  匹配十进制数字
\D  匹配除了十进制数以外的值 
[0-9]  匹配一个0-9之间的数字
[a-z]  匹配小写英文字母
[A-Z]  匹配大写英文字母

最全的常用正则表达式大全

一、校验数字的表达式

  • 数字:[0-9]*$
  • n位的数字:^\d{n}$
  • 至少n位的数字:^\d{n,}$
  • m-n位的数字:^\d{m,n}$
  • 零和非零开头的数字:^(0|[1-9][0-9]*)$
  • 非零开头的最多带两位小数的数字:^([1-9][0-9]*)+(.[0-9]{1,2})?$
  • 带1-2位小数的正数或负数:^(-)?\d+(.\d{1,2})?$
  • 正数、负数、和小数:^(-|+)?\d+(.\d+)?$
  • 有两位小数的正实数:[0-9]+(.[0-9]{2})?$
  • 有1~3位小数的正实数:[0-9]+(.[0-9]{1,3})?$
  • 非零的正整数:[1-9]\d*$ 或 ^([1-9][0-9]){1,3}$ 或 ^+?[1-9][0-9]$
  • 非零的负整数:^-[1-9][0-9]″$ 或 ^-[1-9]\d$
  • 非负整数:^\d+$ 或 [1-9]\d*|0$
  • 非正整数:^-[1-9]\d*|0$ 或 ^((-\d+)|(0+))$
  • 非负浮点数:^\d+(.\d+)?$ 或 [1-9]\d*.\d*|0.\d*[1-9]\d*|0?.0+|0$
  • 非正浮点数:^((-\d+(.\d+)?)|(0+(.0+)?))$ 或 ^(-([1-9]\d*.\d*|0.\d*[1-9]\d*))|0?.0+|0$
  • 正浮点数:[1-9]\d*.\d*|0.\d*[1-9]\d*$ 或 ^(([0-9]+.[0-9][1-9][0-9])|([0-9][1-9][0-9].[0-9]+)|([0-9][1-9][0-9]))$
  • 负浮点数:^-([1-9]\d*.\d*|0.\d*[1-9]\d*)$ 或 ^(-(([0-9]+.[0-9][1-9][0-9])|([0-9][1-9][0-9].[0-9]+)|([0-9][1-9][0-9])))$
  • 浮点数:^(-?\d+)(.\d+)?$ 或 ^-?([1-9]\d*.\d*|0.\d*[1-9]\d*|0?.0+|0)$

二、校验字符的表达式

  • 汉字:[\u4e00-\u9fa5]{0,}$
  • 英文和数字:[A-Za-z0-9]+$ 或 [A-Za-z0-9]{4,40}$
  • 长度为3-20的所有字符:^.{3,20}$
  • 由26个英文字母组成的字符串:[A-Za-z]+$
  • 由26个大写英文字母组成的字符串:[A-Z]+$
  • 由26个小写英文字母组成的字符串:[a-z]+$
  • 由数字和26个英文字母组成的字符串:[A-Za-z0-9]+$
  • 由数字、26个英文字母或者下划线组成的字符串:^\w+$ 或 ^\w{3,20}$
  • 中文、英文、数字包括下划线:[\u4E00-\u9FA5A-Za-z0-9_]+$
  • 中文、英文、数字但不包括下划线等符号:[\u4E00-\u9FA5A-Za-z0-9]+$ 或 [\u4E00-\u9FA5A-Za-z0-9]{2,20}$
  • 可以输入含有^%&’,;=?KaTeX parse error: Undefined control sequence: \” at position 1: \̲”̲等字符:[^%&',;=?\x22]+
  • 禁止输入含有的字符:[^\x22]+

三、特殊需求表达式

  • Email地址:^\w+([-+.]\w+)@\w+([-.]\w+).\w+([-.]\w+)*$

  • 域名:[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(/.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+/.?

  • InternetURL:[a-zA-z]+://[^\s]* 或 ^http://([\w-]+.)+[\w-]+(/[\w-./?%&=]*)?$

  • 手机号码:^(13[0-9]|14[5|7]|15[0|1|2|3|5|6|7|8|9]|18[0|1|2|3|5|6|7|8|9])\d{8}$

  • 电话号码(“XXX-XXXXXXX”、”XXXX-XXXXXXXX”、”XXX-XXXXXXX”、”XXX-XXXXXXXX”、”XXXXXXX”和”XXXXXXXX):^($KaTeX parse error: Undefined control sequence: \d at position 1: \̲d̲{3,4}-)|\d{3.4}…

  • 国内电话号码(0511-4405222、021-87888822):\d{3}-\d{8}|\d{4}-\d{7}

  • 身份证号(15位、18位数字):^\d{15}|\d{18}$

  • 短身份证号码(数字、字母x结尾):^([0-9]){7,18}(x|X)?$ 或 ^\d{8,18}|[0-9x]{8,18}|[0-9X]{8,18}?$

  • 帐号是否合法(字母开头,允许5-16字节,允许字母数字下划线):[a-zA-Z][a-zA-Z0-9_]{4,15}$

  • 密码(以字母开头,长度在6~18之间,只能包含字母、数字和下划线):[a-zA-Z]\w{5,17}$

  • 强密码(必须包含大小写字母和数字的组合,不能使用特殊字符,长度在8-10之间):^(?=.\d)(?=.[a-z])(?=.*[A-Z]).{8,10}$

  • 日期格式:^\d{4}-\d{1,2}-\d{1,2}

  • 一年的12个月(01~09和1~12):^(0?[1-9]|1[0-2])$

  • 一个月的31天(01~09和1~31):^((0?[1-9])|((1|2)[0-9])|30|31)$

  • 钱的输入格式:

    • 有四种钱的表示形式我们可以接受:”10000.00″ 和 “10,000.00″, 和没有 “分” 的 “10000″ 和 “10,000″:[1-9][0-9]*$
    • 这表示任意一个不以0开头的数字,但是,这也意味着一个字符”0″不通过,所以我们采用下面的形式:^(0|[1-9][0-9]*)$
    • 一个0或者一个不以0开头的数字.我们还可以允许开头有一个负号:^(0|-?[1-9][0-9]*)$
    • 这表示一个0或者一个可能为负的开头不为0的数字.让用户以0开头好了.把负号的也去掉,因为钱总不能是负的吧.下面我们要加的是说明可能的小数部分:[0-9]+(.[0-9]+)?$
    • 必须说明的是,小数点后面至少应该有1位数,所以”10.”是不通过的,但是 “10″ 和 “10.2″ 是通过的:[0-9]+(.[0-9]{2})?$
    • 这样我们规定小数点后面必须有两位,如果你认为太苛刻了,可以这样:[0-9]+(.[0-9]{1,2})?$
    • 这样就允许用户只写一位小数。下面我们该考虑数字中的逗号了,我们可以这样:[0-9]{1,3}(,[0-9]{3})*(.[0-9]{1,2})?$
    • 1到3个数字,后面跟着任意个 逗号+3个数字,逗号成为可选,而不是必须:^([0-9]+|[0-9]{1,3}(,[0-9]{3})*)(.[0-9]{1,2})?$
    • 备注:这就是最终结果了,别忘了”+”可以用”*”替代。如果你觉得空字符串也可以接受的话(奇怪,为什么?)最后,别忘了在用函数时去掉去掉那个反斜杠,一般的错误都在这里
  • xml文件:^([a-zA-Z]±?)+[a-zA-Z0-9]+\.[x|X][m|M][l|L]$

  • 中文字符的正则表达式:[\u4e00-\u9fa5]

  • 双字节字符:[^\x00-\xff] (包括汉字在内,可以用来计算字符串的长度(一个双字节字符长度计2,ASCII字符计1))

  • 空白行的正则表达式:\n\s*\r (可以用来删除空白行)

  • HTML标记的正则表达式:<(\S*?)[^>]>.?</\1>|<.*? /> (网上流传的版本太糟糕,上面这个也仅仅能部分,对于复杂的嵌套标记依旧无能为力)

  • 首尾空白字符的正则表达式:^\s*|\s*KaTeX parse error: Undefined control sequence: \s at position 4: 或(^\̲s̲*)|(\s*) (可以用来删除行首行尾的空白字符(包括空格、制表符、换页符等等),非常有用的表达式)

  • 腾讯QQ号:[1-9][0-9]{4,} (腾讯QQ号从10000开始)

  • 中国邮政编码:[1-9]\d{5}(?!\d) (中国邮政编码为6位数字)

  • IP地址:\d+.\d+.\d+.\d+ (提取IP地址时有用)

  • IP地址:((?😦?:25[0-5]|2[0-4]\d|[01]?\d?\d)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d?\d)) (由@飞龙三少 提供,感谢共享)

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值