07 python 要点 (正则化)

  • 参考正则化匹配关键字:   http://caibaojian.com/zhongwen-regexp.html
  • search方法:  扫描整个字符串,并返回第一个成功的匹配
  • march方法:   从起始位置开始匹配,匹配成功返回一个对象,未匹配成功返回None。


第三章 正则表达式

部分常用匹配

  • 匹配中文:[\u4e00-\u9fa5]
  • 匹配双字节字符(包括汉字在内):[^\x00-\xff]
  • 英文字母:[a-zA-Z]  或 [A-z]
  • 数字:[0-9]
  • 匹配中文,英文字母和数字及_: ^[\u4e00-\u9fa5_a-zA-Z0-9]+$           # 同时限制开头结尾
  • 同时判断输入长度:[\u4e00-\u9fa5_a-zA-Z0-9_]{4,10}
  • 一个正则表达式,只含有汉字、数字、字母、下划线不能以下划线开头和结尾:^(?!_)(?!.*?_$)[a-zA-Z0-9_\u4e00-\u9fa5]+$               #  限制开头结尾,同时至少一个字符
  • 匹配5个汉字:/[\x{4e00}-\x{9fa5}]{5}/u               # u不能掉?为啥?

正则表达式,又称正规表示式、正规表示法、正规表达式、规则表达式、常规表示法(英语:RegularExpression,在代码中常简写为regex、regexp或RE),是计算机科学的一个概念。正则表达式使用单个字符串来描述、匹配一系列匹配某个句法规则的字符串。在很多文本编辑器里,正则表达式通常被用来检索、替换那些匹配某个模式的文本

1、re模块

  • 一个正则表达式(或RE)指定了一集与之匹配的字符串;模块内的函数可以让你检查某个字符串是否跟给定的正则表达式匹配
  • 可以使用search来进行匹配第一个最先匹配到的正常的电话号码,而match用来匹配第一个注意是第一个字符的,这里的第一个是在被搜索的这串字符的第一位索引上的

<1> compile方法

re.compile(pattern[,flags])                 # pattern = re.compile(r'1[3,9]\d{9}')

  • 作用:把正则表达式语法转化成正则表达式对象
  • pattern:正则表达式语法
  • flags定义匹配模式包括:
    • re.I:忽略大小写
    • re.L:表示特殊字符集 \w,\W,\b,\B,\s,\S 依赖于当前环境
    • re.M:多行模式
    • re.S:' . '并且包括换行符在内的任意字符(注意:' . '匹配任意字符但不包 括换行符)
    • re.U:表示特殊字符集 \w,\d,\D,\S 依赖于 Unicode 字符属性数据库

<2> search方法

re.search(pattern, string[, flags=0])              #  result = pattern.search(tel_l)

  • 作用:扫描整个字符串,并返回第一个成功的匹配。如果匹配失败,则返回None
  • pattern : 正则表达式对象
  • string : 要被查找替换的原始字符串。
  • flags定义匹配模式包括:
    • re.I:忽略大小写
    • re.L:表示特殊字符集 \w,\W,\b,\B,\s,\S 依赖于当前环境
    • re.M:多行模式
    • re.S:' . '并且包括换行符在内的任意字符(注意:' . '匹配任意字符但不包括换行符)
    • re.U:表示特殊字符集 \w,\d,\D,\S 依赖于 Unicode 字符属性数据库

<3> match方法

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

  • 作用:从起始位置开始匹配,匹配成功返回一个对象,未匹配成功返回None
  • pattern : 正则表达式对象
  • string : 需要匹配的字符串
  • flags定义匹配模式包括:和search方法一致
  • 输出结果:print(result.group(0))
  • 搜索结果解读:
    • 1、re.Match object 对象
    • 2、span= ( )搜索结果在文本索引位置
    • 3、match匹配结果

2、Match对象

我们来看一下,Match对象,Match对象是一次匹配的结果,包含匹配的很多信息

属性与方法描述

pos

搜索的开始位置
endpos搜索的结束位置k
string        搜索的字符串
re当前使用的正则表达式对象
lastindex        

最后匹配的组索引

lastgroup

最后匹配的组名

group(index)

某个组匹配的结果

groups()

所有分组的匹配结果,每个分组组成的结果以列表返回

groupdict()

返回组名作为key,每个分组的匹配结果作为value的字典

start([group])

获取组的开始位置

end([group])

获取组的结束位置

span([group])获取组的开始和结束位置
expand(template)使用组的匹配结果来替换template中的内容,并把替换后的字符串返回
import re

tel_1 = '''    aesdf13811011234    aa1a3hi233rhi3    
87156340    affa124564531346546   afa19454132135    ''' 

pattern = re.compile(r'1[3,9]\d{9}')
results = re.search(pattern, tel_1)

# pos表示搜索的开始的位置,endpos搜索结束的位置 
print(results.pos, results.endpos)   # 0 95
print(results)    # <re.Match object; span=(9, 20), match='13811011234'>
print(results.group())     # 13811011234

3、正则表达式写法

构造正则表达式的方法和创建数学表达式的方法一样。也就是用多种元字符与运算符可以将小的表达式结合在一起来创建更大的表达式。正则表达式的组件可以是单个的字符、字符集合、字符范围、字符间的选择或者所有这些组件的任意组合。正则表达式是由普通字符(例如字符 a 到 z)以及特殊字符(称为"元字符")组成的文字模式。模式描述在搜索文本时要匹配的一个或多个字符串。正则表达式作为一个模板,将某个字符模式与所搜索的字符串进行匹配.

.

匹配任意字符(不包括换行符)

*匹配前一个元字符0到多次
$

匹配结束位置,多行模式下匹配每一行的结束

^匹配开始位置,多行模式下匹配每一行的开始,
+匹配前一个元字符1到多次?

匹配前一个元字符0到1次

{m, n}匹配前一个元字符m到n|逻辑表达式 ,比如 a
\\转义字符,跟在其后的字符将失去作为特殊元字符的含义[ ]

字符集,一个字符的集合,可匹配其中任意一个字符

(...)分组,默认为捕获,即被分组的内容可以被单独取出.(?iLmsux)

分组中可以设置模式,iLmsux之中的每个字符代表一个模式

(?:...)

分组的不捕获模式,计算索引时会跳过这个分组

(?P...)

分组的命名模式,取此分组中的内容时可以使用索引也可以使用name

(?#...)

注释,不影响正则表达式其它部分

(?P=name)

分组的引用模式,可在同一个正则表达式用引用前面命名过的正则.

(?=...)

顺序肯定环视,表示所在位置右侧能够匹配括号内正则.

(?!...)

顺序否定环视,表示所在位置右侧不能匹配括号内正则

(?<=...)

逆序肯定环视,表示所在位置左侧能够匹配括号内正则

(?<!...)逆序否定环视,表示所在位置左侧不能匹配括号内正则
\number

匹配和前面索引为number的分组捕获到的内容一样的字符串

\Z匹配字符串结束位置,忽略多行模式
\A

匹配字符串开始位置,忽略多行模式

\b

匹配位于单词开始或结束位置空字符串

\d匹配一个数字, 相当于 [0-9]\B匹配不位于单词开始或结束位置的空字符串
\D匹配非数字,相当于 [^0-9]\s匹配任意空白字符, 相当于 [ \t\n\r\f\v]
\w

匹配数字、字母、下划线中任意一个字符, 相当于 [a-zA-Z0-9_]

\S匹配非空白字符,相当于 [^ \t\n\r\f\v]
\W

匹配非数字、字母、下划线中的任意字符,相当于[^\w]

<01> 表示字符

.匹配任意单个字符(不包括换行符)
[ ]

匹配字符集,区间中的集合,可匹配其中任意一个字符

\d

匹配数字,即0-9,可以表示为[0-9]

\D

匹配非数字,即不是数字,相当于 [^0-9]

\s

匹配空白字符,即 空格,tab键,相当于 [ \t\n\r\f\v]

\S

匹配非空白字符,相当于 [^ \t\n\r\f\v]

\w

匹配单词字符,即a-z、A-Z、0-9、_

\W

匹配非单词字符,即非数字、字母、下划线中的任意字符,相当于[^\w]

  • print(re.match('.',one))
import re 

# 测试匹配任意字符(不包括换行符)使用的re中的match方法
print(re.match(".","a").group())     # a
print(re.match(".","1").group())     # 1
print(re.match(".","_").group())     # _
print(re.match(".","0").group())     # 0

print(re.match("h","hello Python").group())   # h
print(re.match("[hH]","Hello Python").group())   # H
print(re.match("[0-9]","7Hello Python").group())  # 7
print(re.match("嫦娥1号","嫦娥1号发射成功").group())    # 嫦娥1号
print(re.match("嫦娥\d号","嫦娥1号发射成功").group())   # 嫦娥1号

<02> 转义字符

  •  ' \ ' 在正则表达式中,使用反斜杠进行转义,与其他的方法类似相同
  • 转义特殊字符(允许你匹配 '*' , '?' , 或者此类其他字符),或者表示一个特殊序列我们知道在Python中也存在反斜杠的转义字符,其中我们还有更简便的方法,就是原生字符如果没有使用原始字符串( r'raw' )来表达样式,要牢记Python也使用反斜杠作为转义序列;只有转义序列没有被Python的分析器识别,反斜杠和字符才能出现在字符串中。如果Python可以识别这个序列,那么反斜杠就应该重复两次。这会导致理解上非常的麻烦,所以高度推荐使用原始字符串,就算是最简单的表达式,也要使用原始字符串
  • 我们可以看到, ' \ ' 反斜杠转义字符在实际python字符串中是没有被转义的,但是打印出来的结果中被进行了转义,由我们的python解释器进行转义字符,我们了解到正则表达式中的转义字符也与python中的转义字符类似的规则
  • 举例:print(re.match('C:\\\\',path).group()) /
  • 字符串前面使用r,代表Python中的原生字符串:    #    print(re.match(r'C:\\',path).group())
  • \w还包含了特殊字符:中文、日文等...
import re # 定义变量
path = "c:\\a\\b\\c"
print(path)     # c:\a\b\c     
# 经过正则表达式的转移,四个反斜杠,其中前一个反斜杠对后一个反斜杠进行转移
# 经过一次反斜杠的转以后,再次会通过字符进行转义打印,那这里我们的结果就 生成一个反斜杠
ret = re.match("c:\\\\",path).group()
print(ret)     # c:\
ret = re.match("c:\\\\a",path).group()
print(ret)     # c:\a

<03> 表示数量

*

匹配前一个字符出现0次或者无限次,即可有可无

+

匹配前一个字符出现1次或者无限次,即至少有1次

?

匹配前一个字符出现1次或者0次,即要么有1次,要么没有

{m}

匹配前一个字符出现m次

{m,}

匹配前一个字符至少出现m次

{m, n}

匹配前一个字符出现从m到n次

' * ' 用法:

  • 需求:匹配出,一个字符串第一个字母为大写字母,后面都是小写字母并且这些小写字母可有可无
import re
 
ret = re.match("[A-Z][a-z]*","Mm")
print(ret.group())   # Mm

ret = re.match("[A-Z][a-z]*","Aabcdef")
ret.group()          # 'Aabcdef'

' + ' 用法:

  • 需求:匹配出,变量名是否有效       #  匹配前一个字符出现1次或者无限次,即至少有1次
  • 变量是需要一些条件的,当然现在这里条件不会太过严禁,满足标准标识符结构即可    例如: [a-zA-Z_]+[\w]*
  • 我们的第一个字符产生后,其实可以很明显的看出来这个不仅没有问题,还可以多次列出来,这里我们可以产生 +作为匹配前一个字符出现1次或者无限次,即至少有1次,后面我们可以加上,字母数字下划线,也是用中括号,将\w表示的匹配字母数字下划线,即a-z、A-Z、0-9、_,接着我们使用*,表示这个字符可有可无,我们明白,并不是一定需要第二个字符,有时候我们定义一个变量a也是可以的
  • # [a-zA-Z_]+[\w]*所以这段里面,表示着一个或一个以上的字母下划线,和0或0个以上的字母数字下划线,组合的变量
import re
ret = re.match("[a-zA-Z_]+[\w]*","name1")
print(ret.group())    # name1
ret = re.match("[a-zA-Z_]+[\w]*","_name")
print(ret.group())    # _name
ret = re.match("[a-zA-Z_]+[\w]*","2_n_ame")
print(ret.group())    # 'NoneType' object has no attribute 'group'
re.match("[a-zA-Z_\w]*","n_ame2").group()  # n_ame2

' ? ' 用法:

  • 它匹配前一个元字符0到1次     #  ret = re.match("[1-9]?[0-9]","09")
  • ' {m} ' 用法
  • {m}匹配前一个字符出现m次,{m, n}匹配前一个字符出现从m到n次,但是注意这里的m需要小于n     #  ret = re.match("[a-zA-Z0-9_]{8,20}","1ad12f23s34455ff66")
import re
ret = re.match("[1-9]?[0-9]","7223saf")
print(ret.group())   # 72

ret = re.match("[1-9]?[0-9]","33")
print(ret.group())   # 33

ret = re.match("[1-9]?[0-9]","09")
ret.group()          # 0

<04> 表示边界

^

匹配开始位置,多行模式下匹配每一行的开始, (也有取反的意思,区分应用场景)

$

匹配字符串结尾

\b

匹配一个单词的边界

\B

匹配非单词边界

' ^ ' 用法

  • 用法一: 限定开头    # 限定每行开头
  • 匹配字符串的开头, 并且在 MULTILINE 模式也匹配换行后的首个符号re.MULTILINE 设置以后,样式字符 '^' 匹配字符串的开始,和每一行的开始(换行符后面紧跟的符号);样式字符 '$' 匹配字符串尾,和每一行的结尾(换行符前面那个符号)。默认情况下, ’^’ 匹配字符串头, '$' 匹配字符串尾.                 #  print(re.search('^[a-zA-Z][\w]{5,17}@163\.com$', emails,re.MULTILINE))          
  • 用法二:取反
  • 在某些特定的条件下,在对应的环境中 ^ 所显示的内容是取反的含义,不过需要注意:是[ ]中括号字符集限定中。       #  ret = re.search("[^0-9]", ‘123456’)   
  • MULTILINE 模式(读取多行数据)       #  print(re.search('^[a-zA-Z][\w]{5,17}@163\.com', emails,re.MULTILINE).group())
import re
 
# 定义字符串,害死邮箱的例子 
tel = ''' 225afafaf@163.com
awhahlf@163.com affafafafaaaaaaaaaaaaaaaa@163.com afa_@163.com 225afafaf@163.com'''

pattern1 = r"[a-zA-Z][\w_]{5,17}@163.com"
pattern2 = r"^[a-zA-Z][\w_]{5,17}@163.com"

print(re.search(re.compile(r'[a-zA-Z][\w_]{5,17}@163.com'), tel).group())
# 'afafaf@163.com'  第一种不带 ^ 匹配发现立即匹配到,第二行的邮箱
print(re.search(re.compile(r"^[a-zA-Z][\w_]{5,17}@163.com"), tel))  
# None 第二种带 ^ 匹配发现没有匹配到,我们看到匹配限定,不换行第一行匹配 
re.search(re.compile(r"^[a-zA-Z][\w_]{5,17}@163.com", re.MULTILINE), tel).group()  
# 'awhahlf@163.com' 我们使用了re.MULTILINE,换行匹配查到afa_@163.com, 读取多行首字母开始

' $ ' 用法

  • 匹配字符串尾或者换行符的前一个字符,当然换行符是在 MULTILINE 模式匹配换行符的前一个字符。
  • 例如: foo 可以匹配 'foo' 和 'foobar' , 但正则 foo$ 只匹配 'foo' 。更有趣的是, 在'foo1\nfoo2\n' 搜索 foo.$ ,通常匹配 'foo2' ,但在 MULTILINE 模式 ,可以匹配到 'foo1' ;在'foo\n' 搜索 $ 会找到两个空串:一个在换行前,一个在字符串最后。
import re
# 我们将匹配后缀信息,此时我们没有进行限定结尾
print(re.match("[a-zA-Z][\w_]{5,17}@163\.com", "xiaoWang@163.com").group())  
#  'xiaoWang@163.com'
 
# 这个如果是后缀增加,那我们在筛选的时候就会存在一些问题,因为实际上域名 就已经不对了。
print(re.match("[a-zA-Z][\w_]{5,17}@163\.com", "xiaoWang@163.comheihei").group())
# 'xiaoWang@163.com'
 
# 通过$来确定末尾 
re.match("[a-zA-Z][\w_]{5,17}@163\.com$", "xiaoWang@163.comheihei")   # None

' \b ' 用法

  • ' \b ' 匹配空字符串,但只在单词开始或结尾的位置。一个单词被定义为一个单词字符的序列。注意,通常 \b 定义为 \w 和 \W 字符之间,或者 \w 和字符串开始/结尾的边界, 意思就是 r'\bfoo\b'匹配 'foo' ,'foo.' , '(foo)' , 'bar foo baz' 但不匹配 'foobar' 或者 'foo3',这里就产生了一个概念,单词与字符,单词是一组词组,而字符是包含单字符与多字符。      # print(re.search(r'.*\bchangsha\b','i love changshanan too'))       .
import re
 
# 匹配 bver开头结尾的单词,当然这里面在字符前面还包含了  '.*'号 
re.match(r".*\bver\b", "ho ver abc").group()   # 'ho ver'

' \B ' 用法

  • 匹配空字符串,但不能在词的开头或者结尾。意思就是 r'py\B' 匹配 'python' , 'py3' , 'py2' , 但不匹配'py' , 'py.' , 或者 'py!' . \B 是 \b 的取非,所以Unicode样式的词语是由Unicode字母,数字或下划线构成的,虽然可以用 ASCII 标志来改变。如果使用了 LOCALE 标志,则词的边界由当前语言区域设置。
  • # ASCII:让 `\w`, `\W`, `\b`, `\B`, `\d`, `\D`, `\s` 和 `\S` 只匹配ASCII,而不是Unicode。这只对Unicode样式有效,会被byte样式忽略
  • LOCALE:由当前语言区域决定 `\w`, `\W`, `\b`, `\B` 和大小写敏感匹配。这个标记只能对byte样式有效。这个标记不推荐使用,因为语言区域机制很不可靠,它一次只能处理一个 "习惯”,而且只对8位字节有效。Unicode匹配在Python 3 里默认启用,并可以处理不同语言。
  • \b更多的是针对整个被正则\b限定包含的单词在搜索的环境中是否存在对应的精准值,再上方看到,是使用了空格将独立的单词进行隔离包裹出完整的内容,作为最后的取值结果标准。
  • \B相反,是以非空格形式,将我们的被正则\B限定包含的单词在搜索的环境中是否存在对应的,再上方看到,是使用了非空格将独立的单词进行隔离包裹出完整的内容,作为最后的取值结果标准。
import re
 
# 相同的内容,使用\B进行取反操作, 匹配 ver 非包含开头结尾的单词,还包含了'.*'号 
# 如果未加'.*'号也会报错,注意思路取值是筛选单词与边界相关。
re.match(r".*\Bver\B", "hoverabc").group()  # 'hover'

<5> 表示分组

|

匹配左右任意一个表达式

(ab)

括号中字符作为一个分组

\number

匹配和前面索引为number的分组捕获到的内容一样的字符串

(?P<name>)分组起别名
(?P=name)

引用别名为name分组匹配到的字符串

' | ' 用法 

  • A|B , A 和 B 可以是任意正则表达式,创建一个正则表达式,匹配 A 和 B. 任意个正则表达式可以用 '|' 连接。(它也可以在组合内使用)。扫描目标字符串时, '|' 分隔开的正则样式从左到右进行匹配。当一个样式完全匹配时,这个分支就被接受。意思就是,一旦 A 匹配成功, B 就不再进行匹配,即便它能产生一个更好的匹配。或者说, '|' 操作符绝不贪婪。 如果要匹配 '|' 字符,使用 \| , 或者把它包含在字符集里,比如 [ | ]      # 表示或者
import re
print(re.match("[1-9]?\d$|100","8").group())   #  '8'
print(re.match("[1-9]?\d$|100","78").group())  #  '78'
 
# 当继续匹配100时 依旧使用 | 进行分支匹配,通过右方的表达式进行匹配结果
re.match("[1-9]?\d$|100","100").group()   # '100'

' () ' 用法

  • (组合),匹配括号内的任意正则表达式,并标识出组合的开始和结尾。匹配完成后,组合的内容可以被获取,并可以在之后用 \number 转义序列进行再次匹配,之后进行详细说明。要匹配字符 '(' 或者 ')' , 用 \( 或\) , 或者把它们包含在字符集合里: [ ( ] , [ ) ] .
import re

# 这里常规测试邮箱,无边界限定,匹配正常
print(re.match("\w{4,20}@163\.com", "test@163.com").group())   # 'test@163.com'
 
# 在括弧中加入了分支进行判断,根据结果判断,也匹配到结果
print(re.match("\w{4,20}@(163|126|qq)\.com", "test@126.com").group())  
# 结果: 'test@126.com'
# 如法炮制在匹配对应的分支判断下,在小括号中的分支,留下对应的其中一组结果。
print(re.match("\w{4,20}@(163|126|qq)\.com", "test@qq.com").group())   
# 结果: 'test@qq.com'
# 只有当不在对应的值内匹配即存在无法识别的问题
print(re.match("\w{4,20}@(163|126|qq)\.com", "test@gmail.com"))   # None

' \number ' 用法

  • 上面说到在()分组中,可以只用 \number 进行转义操作了解 \ 可以调节转义字符,但是当后面加上数字,则存在特殊序列,由 '\' 和一个字符组成的特殊序列。
  • 匹配数字代表的组合。每个括号是一个组合,组合从1开始编号。比如 (.+) \1 匹配 'the the' 或者 '5555' , 但不会匹配 'thethe' (注意组合后面的空格)。这个特殊序列只能用于匹配前面99个组合。如果 number 的第一个数位是0, 或者 number 是三个八进制数,它将不会被看作是一个组合,而是八进制的数字值。在 '[' 和']' 字符集合内,任何数字转义都被看作是字符。
import re
 
# 进行匹配,首先是首位的标签,头部 <[a-zA-Z]*> 中间 \w*  尾部 <[a-zA-Z]*>,完成匹配
print(re.match("<[a-zA-Z]*>\w*</[a-zA-Z]*>", "<html>hh</html>").group())  
#  '<html>hh</html>'

# 进行匹配,首先是首位的标签,头部 <[a-zA-Z]*> 中间 \w*  尾部 <[a-zA-Z]*>
print(re.match("<[a-zA-Z]*>\w*</[a-zA-Z]*>", "<html>hh</htmlbalabala>").group())  
# '<html>hh</htmlbalabala>'

# 那此时我们明白,无论你的前面是何种类型的标签,后方结束标签理论上是需要一致的匹配结构 
# 那这里就引出一个分组的概念,每个括号是一个组合,组合从1开始编号, 尾部进行选择编号 
re.match(r"<([a-zA-Z]*)>\w*</\1>", "<html>hh</html>").group()  # '<html>hh</html>'

' (?P) (?P=name) ' 用法

  • ?P<要起的别名> (?P=起好的别名)
  • (?P):(命名组合)类似正则组合,但是匹配到的子串组在外部是通过定义的 name 来获取的。组合名必须是有效的Python标识符,并且每个组合名只能用一个正则表达式定义,只能定义一次。一个符号组合同样是一个数字组合,就像这个组合没有被命名一样。命名组合可以在三种上下文中引用。如果样式是 (?P<quote>['"]).*?(?P=quote) (也就是说,匹配单引号或者双引号括起来的字符串):
  • 注意: (?P<name>) 和 (?P=name) 中的字母p大写
import re
 
s = '<html><h1>我是一号字体</h1></html>' 
# pattern = r'<(.+)><(.+)>.+</\2></\1>' 
# 如果分组比较多的话,数起来比较麻烦,可以使用起别名的方法?P<要起的名字> 
# 以及使用别名(?P=之前起的别名) 
pattern = r'<(?P<key1>.+)><(?P<key2>.+)>.+</(?P=key2)></(?P=key1)>' 
print(re.match(pattern, s).group())

<6> RE模块高级使用

search

  • 作用:扫描字符串,查找正则表达式模式产生匹配的第一个位置,并返回对应的匹配对象。如果字符串中没有位置与模式匹配,则返回None; 注意,这不同于在字符串的某个点上找到长度为零的匹配。
  • 需求:匹配出文章阅读的次数
import re
 
# match方法 
print(re.match('\d+','阅读次数为 9999 次'))  # None
# search方法
print(re.search('\d+','阅读次数为 999 次').group())   # 999

findall

  • 参数:re.findall(pattern, string, flags=0)
  • 作用:pattern 在 string 里所有的非重复匹配,返回为一个迭代器 iterator保存了 匹配对象 。 string 从左到右扫描,匹配按顺序排列。空匹配也包含在结果里。也就是说以字符串列表的形式返回所有的非重叠的匹配结果。从左到右扫描字符串,并按照找到的顺序返回匹配项,如果存在一个或多个字符串,返回一个列表的组织;如果匹配表达式中有多个分组,这将是一个元组列表。结果中包含空匹配项。
  • 注意:在 3.7 版更改: 非空匹配现在可以在前一个空匹配之后出现了                      # lst = re.findall('(^[a-zA-Z][\w]{5,17}@(163|126)\.com$)', emails,re.MULTILINE)
import re
 
# 匹配多组,返回列表
print(re.findall(r'\d+',"阅读次数C:129 Python:999 C++:99"))  # ['129', '999', '99']

sub

  • 参数:re.sub(pattern, repl, string, count=0, flags=0)
  • 作用:返回repl字符串或者调用repl函数而得到的字符串。如果没有找到,则返回字符串不变
  • 需求:将匹配到的阅读次数加1
import re
 
# 匹配对应的
print(re.sub(r"\d+", '992', "python = 997"))  # python = 992

split

  • 参数:re.split(pattern, string, maxsplit=0, flags=0)
    • pattern:相当于str.split()中的sep,分隔符的意思,不但可以是字符串,也可以为正则表达式:'[ab]',表示的意思就是取a和b的任意一个值
    • string:要进行分割的字符串
    • maxsplit:分割的最大次数,这个参数和str.split()中有点不一样,默认值为0,表示分割次数无限制,能分几次分几次;取负数,表示不分割;若大于0,表示最多分割maxsplit次;
    • flags:该参数可以用来修改pattern表达式的功能,比如忽略大小写 re.IGNORECASE(简写:re.I),即当flags = re.IGNORECASE ,pattern = [A-Z]不但能匹配到大写字母,也能匹配到小写字母。
import re

# 正则分割,这里是大写W,分割的是 非字母数字下划线 
print(re.split(r'\W+', 'Words, words, words.'))  # ['Words', 'words', 'words', '']

print(re.split(r'(\W+)', 'Words, words.'))   #  ['Words', ', ', 'words', '.', '']

print(re.split(r'\W+', 'Words, words, words.', 1))  # ['Words', 'words, words.']
# 表示通过使用字母分割,这里加上re.IGNORECASE表示忽略大小写分割 
re.split('[a-f]+', '0a3B9', flags=re.IGNORECASE)   # ['0', '3', '9']

贪婪与非贪婪

  • Python里数量词默认是贪婪的, 总是尝试匹配尽可能多的字符.
  • 与贪婪相反,总是尝试匹配尽可能少的字符,可以使用"*","?","+","{m,n}"后面加上?,使贪婪变成非贪婪正则表达式模式中使用到通配字,那它在从左到右的顺序求值时,会尽量“抓取”满足匹配最长字符串,在我们上的例子里面,“.+”会从字符串的启始处抓取满足模式的最长字符,其中包括我们想得到的第一个整型字段的中的[]部分,“\d+”只需一位字符就可以匹配,所以它匹配了数字“4”,而“.+”则匹配了从字符串起始到这个第一位数字4之前的所有字符。
  • 解决方式:非贪婪操作符 “ ?”,这个操作符可以用在"*","+","?"的后面,要求正则匹配的越少越好。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值