找回密码
 会员注册
查看: 33|回复: 0

Python基础(标准库):re(正则表达式操作)

[复制链接]

2万

主题

0

回帖

7万

积分

超级版主

积分
71910
发表于 2024-9-7 01:02:48 | 显示全部楼层 |阅读模式
1.官方文档(中英文)re—Regularexpressionoperations—Python3.12.2documentationre---正则表达式操作—Python3.12.2文档2.正则表达式语法阅读2.1~2.3前,请先简单浏览一下、、。2.1 点号'.'(点号)在默认模式下,匹配除换行符以外的任意字符。如果指定了旗标DOTALL ,它将匹配包括换行符在内的任意字符。#示例1text1='a1$5\ns're1=re.compile('.')re2=re.compile('.',flags=re.DOTALL)result1=re1.findall(text1)result2=re2.findall(text1)print(result1)print(result2)#返回结果#['a','1',','5','s']#['a','1',','5','\n','s']2.2'^'(插入符)匹配字符串的开头,并且在MULTILINE模式下也匹配换行后的首个符号。#示例2text1='haha\nhaha'text2='\nhaha'text3='haha're1=re.compile('^.')re2=re.compile('^.',flags=re.MULTILINE)result11=re1.findall(text1)result12=re1.findall(text2)result13=re1.findall(text3)result21=re2.findall(text1)result22=re2.findall(text2)result23=re2.findall(text3)print(f're1:{result11},{result12},{result13}')print(f're2:{result21},{result22},{result23}')#返回结果:#re1:['h'],[],['']#re2:['h','h'],['h'],['']2.3'匹配字符串尾或者在字符串尾的换行符的前一个字符,在MULTILINE模式下也会匹配换行符之前的文本。#示例3$text1='haha'text2='haha\n'text3='haha\n\n'text4='haha\n\nha're1=re.compile(')re2=re.compile('.)re3=re.compile('.,flags=re.MULTILINE)result11=re1.findall(text1)result12=re1.findall(text2)result13=re1.findall(text3)result14=re1.findall(text4)result21=re2.findall(text1)result22=re2.findall(text2)result23=re2.findall(text3)result24=re2.findall(text4)result31=re3.findall(text1)result32=re3.findall(text2)result33=re3.findall(text3)result34=re3.findall(text4)print(f're1:{result11},{result12},{result13},{result14}')print(f're2:{result21},{result22},{result23},{result24}')print(f're3:{result31},{result32},{result33},{result34}')#返回结果#re1:[''],['',''],['',''],['']##在'foo\n'中搜索$会找到两个(空的)匹配:一个在换行符之前,一个在字符串的末尾。#re2:['a'],['a'],[],['a']##.不匹配换行符#re3:['a'],['a'],['a'],['a','a']###re3=re.compile('.,flags=re.MULTILINE|re.DOTALL)###返回值为:re3:['a'],['a','\n'],['a','\n','\n'],['a','\n','a']###re1=re.compile(',flags=re.MULTILINE)###返回值为:re1:[''],['',''],['','',''],['','','']2.4 数量限定符'*','+','?'尽量多的匹配字符串(贪婪的)*对它前面的正则式匹配0到任意次重复ab* 会匹配'a','ab',或者 'a'后面跟随任意个 'b'+对它前面的正则式匹配1到任意次重复ab+ 会匹配 'ab',或 'a' 后面跟随任意个'b',不会匹配 'a'? 对它前面的正则式匹配0到1次重复ab? 会匹配'a' 或者'ab're.findall('A*','AAA123AAAAA456')#返回结果#['AAA','','','','AAAAA','','','','']re.findall('A+','AAA123AAAAA456')#返回结果#['AAA','AAAAA']re.findall('A?','AAA123AAAAA456')#返回结果#['A','A','A','','','','A','A','A','A','A','','','','']2.5非贪婪数量限定符'*?','+?','??'re.findall('((A+)(.*)(B+))','AAAabcBBB')#[('AAAabcBBB','AAA','abcBB','B')]re.findall('((A+)(.*?)(B+))','AAAabcBBB')#[('AAAabcBBB','AAA','abc','BBB')]不管是贪婪模式,还是非贪婪模式,都需要发生回溯才能完成相应的功能。#式子1re.findall('Y*Z','YYZ')#返回结果#['YYZ']#式子2re.findall('Y*?Z','YYZ')#返回结果#['YYZ']#式子3re.findall('Y??Z','YYZ')#返回结果#['YZ']式子1在匹配时,'Y*'会尽可能多地去匹配,当匹配完'YY'后,继续用正则'Y'与下一个字符'Z'匹配,匹配不上,这时就会发生回溯,吐出当前字符'Z',接着用正则'Z'去匹配,匹配成功。式子2在匹配时,'Y*?'匹配上一个'Y'后,使用下一个正则'Z'与下一个文本内容'Y'比较,发现不匹配,这时向前回溯,重新查看'Y'匹配两个的情况,匹配上'YY',然后再用正则'Z'去匹配文本中的'Z',匹配成功。2.6 重复运算符'{m}','{m,n}'注意'{m,n}',逗号后没有空格尽量多的匹配字符串(贪婪的){m}对其之前的正则式指定匹配 m 个重复;少于 m 的话就会导致匹配失败。a{6} 将匹配6个 'a' ,但是不能是5个{m,n}对正则式进行 m 到 n 次匹配,在 m 和 n 之间取尽量多;忽略 m 意为指定下界为0,忽略 n 指定上界为无限次;逗号不能省略,否则无法辨别修饰符应该忽略哪个边界。a{4,}b 将匹配 'aaaab' 或者1000个 'a' 尾随一个 'b',但不能匹配 ‘aaab’2.7 非贪婪重复运算符'{m,n}?''{m}'固定次数,因而没必要用'{m}?'re.findall('1{3,5}','11111111aaa')#['11111','111']re.findall('1{3,5}?','11111111aaa')#['111','111']2.8 转义字符'\'正则表达式使用反斜杠'\'作为转义字符,以便匹配字符'*','?'等此类字符;或者表示特殊序列,如\w、\W、\d、\D等。Python也使用反斜杠作为转义字符,Python中反斜杠符号用'\\'表示;或者使用raw字符串(原始字符串r'')表示为r'\',r''的功能就是把如"\"变成"\\",从而使转义失效,简单来说,使用r''的效果就是:所见即所得。因而在正则表达式中,想表示星号,可使用'\*'(Python中,\*没有特殊含义,仅以普通格式输出,\*只代表\*),r'\*',或者'\\*';想表示反斜杠,应该使用'\\\\'或者r'\\'。 re.findall('\*','\*')#正则表达式'\*',匹配星号*,返回['*']re.findall('\\*','\*')#正则表达式'\*',匹配星号*,返回['*']re.findall(r'\*','\*')#正则表达式'\*',匹配星号*,返回['*']re.findall('\\\*','\*')#正则表达式'\\*',匹配0个或者多个\#['\\','','']re.findall(r'\\*','\*')#正则表达式'\\*',匹配0个或者多个\#['\\','','']re.findall('\\\+','\*')#正则表达式'\\+',匹配1个或者多个\#['\\']re.findall('\d\\\\1',r'1234\15678\1')#正则表达式'\d\\1',匹配一个数字+字符'\'+数字1#['4\\1','8\\1']re.findall(r'\d\\1',r'1234\15678\1')#正则表达式'\d\\1',匹配一个数字+字符'\'+数字1#['4\\1','8\\1']#re.findall('\\1',r'\1')#正则表达式'\1',引用第一个分组,但是之前又没有()产生的分组,故而报错#报错:invalidgroupreference1atposition12.9 字符集'[]'字符可以单独列出,比如 [amk] 匹配 'a', 'm',或者 'k'。通过用 '-' 将两个字符连起来,表示字符范围。比如 [a-z] 将匹配任何小写ASCII字符;[0-5][0-9] 将匹配从 00 到 59 的两位数字;[0-9A-Fa-f] 将匹配任何十六进制数位。如果 - 进行了转义(比如 [a\-z])或者它的位置在首位或者末尾(如 [-a] 或 [a-]),它就只表示普通字符 '-'​​​​​​​。特殊字符在集合中会失去其特殊意义。比如[(+*)] 只会匹配这几个字面字符之一:'(', '+','*'或')'。字符类如 \w 或者 \S (定义如下)也在集合内被接受(参考 部分),不过它们可匹配的字符依赖于所使用的 flags。不在集合范围内的字符可以通过取反来进行匹配。如果集合首字符是 '^'​​​​​​​ ,所有不在集合内的字符将会被匹配,比如 [^5] 将匹配所有字符,除了'5', [^^] 将匹配所有字符,除了 '^',^ 如果不在集合首位,就没有特殊含义。要在集合内匹配一个']' 字面值,可以在它前面加上反斜杠,或是将它放到集合的开头。例如,[()[\]{}] 和 []()[{}] 都可以匹配右方括号,以及左方括号,花括号和圆括号。2.10 或操作'|',对于'A|B',一旦A匹配成功, B就不再进行匹配,即便B能产生一个更好的匹配,或操作是不贪婪的。re.findall('(?:abc){2}|[a-z]{6}','qwertyuioabcabc123243432abcabc')#返回结果#['qwerty','uioabc','abcabc']re.findall('(?:abc){2}|(?:abc){3}','1abcabcabc2abcabcabc3abcabcabc')#返回结果#['abcabc','abcabc','abcabc']re.findall('(?:abc){3}|(?:abc){2}','1abcabcabc2abcabcabc3abcabcabc')#返回结果#['abcabcabc','abcabcabc','abcabcabc']2.11 ython不支持,跳过:占有型数量限定符'*+','++','?+'这种模式类似与贪婪模式,会尽可能多地去匹配,但不会进行回溯,如果匹配失败就结束,这样比较节省时间。不过Python不支持这种模式,会将+理解为数量限定符,报错:multiplerepeat,(不支持这种写法,与'**','+*',报错相同:多个重复)含义如下(如果需要这个功能,参见,安装regex 模块):2.12 ython不支持,跳过:占有型重复运算符'{m,n}+'报错同2.11,含义如下: 2.13'(...)' 普通捕获组,将表达式匹配的内容保存到以数字编号的组里,编号规则是以'('从左到右出现的顺序,从1开始进行编号。通常情况下,编号为0的组表示整个表达式匹配的内容。要匹配字符'(' 或者')',用'′或′′或′',或者把它们包含在字符集合里:[(] 或[)]。分组的概念在Match对象(匹配对象)中很重要,Match对象是re中两个非常常用的方法search()和match()的返回值,因而,阅读后续内容前,请先简单浏览一下、、、。obj=re.match('([a-zA-Z]+)([0-9]+)([a-zA-Z]+)([0-9]+)','aBc123dEf456')obj.groups()obj.group(0)obj.lastindexobj.group(0,1,2,3,4)obj.groupdict()#('aBc','123','dEf','456')#'aBc123dEf456'#4#('aBc123dEf456','aBc','123','dEf','456')#{}接下来介绍一些扩展标记法,形如'(?…)''?' 后面的第一个字符决定了这个构建采用什么样的语法。除'?P...)' 外,这种扩展通常并不创建新的组合。2.14 (?P…)命名捕获组,可以通过捕获组名而不是序号对捕获组内容进行引用,这种便捷的引用方式,不用关注捕获组的序号,也不用担心表达式部分变更会导致引用错误的捕获组。s='1102231990xxxxxxxx'res=re.search('(?P [0-9]{3})(?P[0-9]{3})(?P[0-9]{4})',s)print(res.groupdict())#返回结果#{'province':'110','city':'223','born_year':'1990'}2.15 (?:...) 非捕获组,将匹配内容保存到最终的整个表达式的区配结果中,但Expression匹配的内容不单独保存到一个组内。re.match('(A+)(?:.*)(B+)','AAA123abcBBB').group(0,1,2)#返回结果#('AAA123abcBBB','AAA','B')re.match('(A+)(?:.*)(B+)','AAA123abcBBB').group(0,1,2,3)#报错nosuchgroup2.16'(?P=name)'反向引用一个命名组合,不会增加新的组;它匹配前面那个叫 name 的命名组中匹配到的串同样的字串。re.match(r'(?P[\w]+).*?(?P=name)-(\d+)','AnnaSmith@123AnnaSmith-1398383720').groups()#返回结果#('AnnaSmith','1398383720')2.17'(?#...)'注释模式,在实际工作中,正则可能会很复杂,导致编写、阅读和维护正则都会很困难,添加注释能便够便于阅读和维护,正则中注释模式使用 '(?#...)' 来表示。re.search('(?#abcabc)((abc)+)','abcabcabc').group(0,1,2)#返回结果#('abcabcabc','abcabcabc','abc')re.search('(?#abcabc)((?:abc)+)','abcabcabc').group(0,1)#返回结果#('abcabcabc','abcabcabc')2.18~2.21 的主题为环视环视是一种特殊的正则语法,从本质上来说,它匹配的是位置,正则表达式用来限定这个位置的左右应该是什么或者应该不是什么,然后去寻找这个位置;环视中的正则表达式只进行匹配,匹配内容不计入最终的匹配结果。环视中虽然也有括号,但不会保存成子组。环视中的表达式应该是固定长度的(look-behindrequiresfixed-widthpattern)。2.18'(?=...)'顺序肯定环视,表示所在位置右侧能够匹配Expression可应用于文件名处理,如:要求文件名只能以字母或下滑线开头时,对文件名的规范化操作:re.sub含义参考6.7;\W参考 re.sub('\W|^(?=\d)','_','1asd')#'_1asd're.sub('\W|^(?=\d)','_','+asd')#'_asd'2.19'(?)来源:正则表达式校验之逗号分割的不重复单个字母-知乎)目标:用正则校验以逗号分隔的字符串且其中不可存在重复的子串。例如,有两个字符串:'Q,WW,EEE,1111,rrr222”和“A,SS,DDD,3333,fff444,SS',前者符合要求,后者不符合,因为后者里面的“SS”子串出现了两次。解答如下,主要应用了顺序否定环视语法,同时可以体会一下复杂句式中运用命名捕获组的优势。text0="AA,SS,DDD,SS,BB"re.match(r'(^|.*,)(?P[^,]+)(?:,.*,|,)(?P=repeat)(?:,.*|$)',text0).group(0)#匹配成功,返回"AA,SS,DDD,SS,BB"#在这个句式中,注意要保证:1.repeat组在句子开始,或者前后都有逗号;2.后向引用的repeat组前面一定有个逗号,且除在句末否则其后也有逗号。这两点要求用以避免两个子串部分内容相同的场景被错误地视作为重复子串。pattern=re.compile(r'(?!(^|.*,)(?P[^,]+)(?:,.*,|,)(?P=repeat)(?:,.*|$))[^,]+(,[^,]+)+')text1="Q,WW,EEE,1111,rrr222"text2="SS,SS"text3="SS,DDD,SS"text4="AA,SS,DDD,SS"text5="AA,SS,DDD,SS,BB"text6="SSabc,SSabcdef,DDD,3333,fff444"text7="SSabc,defSSabc,DDD,3333,fff444"pattern.match(text1)#匹配成功--'Q,WW,EEE,1111,rrr222'pattern.match(text2)#Nonepattern.match(text3)#Nonepattern.match(text4)#Nonepattern.match(text5)#Nonepattern.match(text6)#匹配成功--'SSabc,SSabcdef,DDD,3333,fff444'pattern.match(text7)#匹配成功--'SSabc,defSSabc,DDD,3333,fff444'2.21'(?设置相应的旗​​​​​​​标。效果同flag,具体含义参见下文re.findall(r'(^.)','haha\nxixi\n\nenen',flags=re.MULTILINE|re.DOTALL)#['h','x','\n','e']re.findall(r'(.$)','haha\nxixi\n\nenen',flags=re.MULTILINE|re.DOTALL)#['a','i','\n','n']re.findall(r'(?ms)(^.)','haha\nxixi\n\nenen')#['h','x','\n','e']re.findall(r'(?ms)(.$)','haha\nxixi\n\nenen')#['a','i','\n','n']re.findall(r'(^.)','haha\nxixi\n\nenen',re.M|re.S)#['h','x','\n','e']re.findall(r'(.$)','haha\nxixi\n\nenen',re.M|re.S)#['a','i','\n','n']text="Hello\World\HELLO\WORLD"re.findall(r'(?mi)hello',text)#['Hello','HELLO']2.23'(?aiLmsux-imsx:…)','?'后面是零个或多个来自'a','i','L','m','s','u','x'​​​​​​​集合的字母,后面可以带 '-'​​​​​​​ 再跟1个或多个来自'i','m','s','x' 集合的字母,这些字母将为设置或移除相应的旗标。如'(?m-i:...)','(?m:...)'等。re.findall(r'(?i)aA','aA-Aa-AA-aa')#['aA','Aa','AA','aa']re.findall(r'(?i:a)A','aA-Aa-AA-aa')#['aA','AA']re.findall(r'(?i:a)A','aA-Aa-AA-aa',flags=re.I)#['aA','Aa','AA','aa']re.findall(r'(?-i:a)A','aA-Aa-AA-aa',flags=re.I)#['aA','aa']re.findall(r'(?i)(?-i:a)A','aA-Aa-AA-aa')#['aA','aa']#re.findall(r'(?is-i:.aa)','AAaaAaaA\naaAa')#报错badinlineflags:flagturnedonandoffatposition62.24'(?(id/name)yes-pattern|no-pattern)'re.match('(|$))','user@host.com').group(0,1,2)#('user@host.com',None,'user@host.com')re.match('(|$))','').group(0,1,2)#('','')re.match('(|$))','|$))','user@host.com>')#None Unicode和ASCII的区别ASCII编码是美国标准信息交换码(American Standard Codefor Information Interchange),主要用于显示现代英语。Unicode: (万国码、国际码、统一码、单一码)是计算机科学领域里的一项业界标准。它对世界上大部分的文字系统进行了整理、编码,使得计算机可以用更为简单的方式来呈现和处理文字。总的来说,Unicode编码是ASCII编码的扩展,它可以表示更多的字符,并且支持多种语言。1.ASCII编码只能表示英文字母、数字、标点符号和一些控制字符,共计128个字符。而Unicode编码可以表示世界上几乎所有的字符,包括各种语言的文字、符号、表情等,共计超过13万个字符。2.ASCII编码使用7位二进制数表示一个字符,最高位始终为0。而Unicode编码使用16位二进制数表示一个字符,可以表示更多的字符。3.Unicode和ASCII是字符集,而UTF-8/UTF-16/UTF-32都是编码规则。Unicode是一个标准,UTF-8是实现,UTF-8以字节为单位对Unicode进行编码。4.示例当Unicode模式[a-z]或[A-Z]与 IGNORECASE旗标(忽略大小写匹配)一起使用时,它们将匹配52个ASCII字母和4个额外的非ASCII字母:'İ'(U+0130,大写拉丁字母I带有上方的点),'ı'(U+0131,小写拉丁字母i不带上方的点),'ſ'(U+017F,小写拉丁字母长s)和'K'(U+212A,开尔文标记)。如果使用了 ASCII旗标,则只匹配字母'a'到'z'和'A'到'Z'。\A只匹配字符串开始。\Z只匹配字符串尾。\b匹配空字符串,但只在单词开始或结尾的位置。\B匹配空字符串,但仅限于它不在单词的开头或结尾的情况。\d匹配任意Unicode十进制数码,这包括[0-9],还包括许多其他的数码类字符。如果使用了ASCII旗标则匹配 [0-9]。\D匹配不属于Unicode十进制数码的任意字符,与 \d 正相反。如果使用了 ASCII 旗标则匹配 [^0-9]。\s匹配Unicode空白字符,包括[\t\n\r\f\v],还包括许多其他字符。\S匹配不属于Unicode空白字符的任意字符,与 \s 正相反。如果使用了ASCII旗标则匹配[^\t\n\r\f\v]。\w匹配Unicode单词类字符,包括所有Unicode字母数字类字符(由 str.isalnum()定义),以及下划线(_)。如果使用了ASCII旗标则匹配[a-zA-Z0-9_]。可以用r'\b\w+\b'匹配单词\W匹配不属于Unicode单词类字符的任意字符,与\w正相反。在默认情况下,将匹配除下划线(_)以外的 str.isalnum()返回False的字符。如果使用了ASCII旗标则匹配[^a-zA-Z0-9_]。\number组合从1开始编号,用\number匹配数字代表的组合。参考下方细节说明-1。1.简单说明Python中,除'\number'和'\b'外(python中,\b表示Backspace退格,正则表达式中,\b表示单词开始和结束位置的空字符,如果想在正则表达式内表示退格,要将其放在字符集合内:[\b]),上述 '\+ASCII字母'形式的特殊序列,在Python中均以普通格式输出,因而在表示正则表达式时,即便没有使用原始字符串r'',也不会产生问题;但是涉及 '\number'和'\b'时,切记要用原始字符串的形式r''。re.findall('\b','helloworld')#[]re.findall(r'\b.?','helloworld')#['h','','w','']re.findall(r'\b\w+\b','RichardFeynmanisafamousphysicist')#['Richard','Feynman','is','a','famous','physicist']re.findall('.[\b]','hello\bworld')#['o\x08']2.'\number'1)要使用原始字符串r'\1'或者'\\1',否则表示的是python中的转义字符'\1';2)必须存在对应序号的分组,否则会报错。text='thethelittlecatcatisinthehathathat,welikeit.'re.findall(r'(\w+)((?:\s+\1)+)',text) #返回结果:[('the','the'),('cat','cat'),('hat','hathat')]re.findall('\1',r'12344\1')#[]匹配失败re.findall('\1','12344\1')#['\x01']匹配成功#re.findall(r'\1',r'12344\1')#前面没有分组,报错nvalidgroupreference1atposition1re.findall('(\d)\1',r'12344\1')#[]\1表示python中的\1(方框里面带一个问号)re.findall('(\d)\\1',r'12344\1')#['4']re.findall(r'(\d)\1',r'12344\1')#['4']如果有且仅有一个组,返回与该组匹配的字符串列表re.search(r'(\d)\1',r'12344\1').group(0)#'44'3.正则对象RegularExpressionObjects由 re.compile()返回的已编译正则表达式对象。正则表达式对象的对象方法与re中的函数基本一致(部分函数多了两个可选参数pos和endpos,能限制搜索范围)。方法或属性描述细节Pattern.search(string[, pos[, endpos]])类似于函数search()(1)可选参数 pos 给出了字符串中开始搜索的位置索引,默认为0,不过这不完全等价于字符串切片:元字符‘^'可匹配字符串真正的开头、换行符后面的第一个字符,但不会匹配由pos规定开始的位置。(2)可选参数 endpos 限定了字符串搜索的结束位置,它假定字符串长度到 endpos ,所以只有从 pos 到 endpos-1 的字符会被匹配。如果 endpos 小于 pos,就不会有匹配产生;pattern.search(string,0,50)等价于 pattern.search(string[:50],0)。Pattern.match(string[, pos[, endpos]])类似于函数match()可选参数 pos\endpos 与search() 含义相同;用于限制搜索范围。Pattern.fullmatch(string[, pos[, endpos]])类似于函数fullmatch()可选参数 pos\endpos 与search() 含义相同;用于限制搜索范围。Pattern.findall(string[, pos[, endpos]])类似于函数findall()可选参数 pos\endpos 与search() 含义相同;用于限制搜索范围。Pattern.finditer(string[, pos[, endpos]])类似于函数finditer()可选参数 pos\endpos 与search() 含义相同;用于限制搜索范围。Pattern.sub(repl, string, count=0)等价于函数sub() --Pattern.subn(repl, string, count=0)等价于函数subn() --Pattern.split(string, maxsplit=0)等价于函数split()--Pattern.flags--正则表达式匹配旗标:传给compile() 的旗标组合,模式中的任何(?...)内联旗标,以及隐式旗标如UNICODE。Pattern.groups--捕获到的模式串中组的数量。Pattern.groupindex--映射由(?P)定义的命名符号组合和数字组合的字典。如果没有符号组,那字典就是空的。Pattern.pattern--编译对象的原始样式字符串。pattern1=re.compile(r'^([a-z])(\w?\d+)(?P\s*)',re.I|re.A)pattern2=re.compile(r'([a-z])(\w?\d+)(?P\s*)',re.I|re.A)text='aa11123'pattern1.match(text).group(0)#'aa11'#其他属性值pattern1.flags#258pattern1.groups#3pattern1.groupindex#mappingproxy({'name1_group':3})pattern1.pattern#'^([a-z])(\\w?\\d+)(?P\\s*)'#有^时,pos不等于1将匹配不到pattern1.match(text,1)#Nonepattern2.match(text)#pattern2.match(text,1)#注意:(1)flags打印值为258,对应re.ASCII|re.IGNORECASE,其他旗标对应值参考;(2)'^'不能匹配由pos规定的开始位置,在上述例子中,pattern1有'^',使用re.mathc()且pos设置为1时,匹配不到结果,返回None。4.匹配对象MatchObjects由成功的match 和search 所返回的匹配对象。方法或属性描述Match.group([group1, ...])返回一个或者多个匹配的子组。如果只有一个参数,结果就是一个字符串,如果有多个参数,结果就是一个元组(每个参数对应一个项),如果没有参数,默认为0,整个匹配。参数支持组号(组索引值)、字符串(组名),如:re.match('(a)(b)(c)','abc').group(0,1,2)re.match('(a)(b)(?Pc)','abc').group(0,1,'name')。如果传入字符串参数(组名),但在pattern中不存在此组名,会引发IndexError异常;如果一个组号是负数,或者大于样式中定义的组数,会引发IndexError异常。如果一个组匹配成功多次,就只返回最后一个匹配,如:re.match(r"(..)+","a1b2c3").group(1)的返回值是'c3'。Match.groups()返回一个元组,包含所有匹配的子组(在pattern中出现的从1到任意多的组合)。 没有分组返回()Match.groupdict()返回一个字典,包含了所有的命名子组:key是组名,value是匹配的值;没有分组返回{}Match.__getitem__(g)等价于Match.group(g),如,可以通过Match[0],获取第一个分组的内容,即Match.group(0)。Match.start([group])返回 group 匹配到的字串的开始标号。Match.end([group])返回 group 匹配到的字串的结束标号。Match.span([group])返回一个二元组(m.start(group),m.end(group))。如果group没有在这个匹配中,就返回(-1,-1)。group默认为0,表示整个匹配。Match.pos正则引擎开始在字符串搜索一个匹配的位置索引。Match.endpos正则引擎停止在字符串搜索一个匹配的位置索引。Match.lastindex捕获组的最后一个匹配的整数索引值,如果没有的话返回None。比如,对于字符串'ab',表达式 '(a)b', '((a)(b))',和'((ab))'将得到lastindex== 1,而 '(a)(b)' 会得到 lastindex==2 。Match.lastgroup最后一个匹配的命名组名字,如果没有的话返回None。Match.re返回产生这个实例的正则对象()。Match.string返回传递到 match()或search()的字符串。先看一个示例:matchobj=re.match(r'^([a-z])([a-z]?[0-9]+)(?P[,\n\t]*)(?P[0-9]+)([0-9]?)','aa11123')matchobj.pos#0matchobj.endpos#8matchobj.lastindex#5matchobj.lastgroup#Nonematchobj.re#re.compile(r'^([a-z])([a-z]?[0-9]+)(?P[,\n\t]*)(?P[0-9]+)([0-9]?)',re.UNICODE)matchobj.re.groups#5matchobj.string#'aa11123'matchobj.re.pattern#'^([a-z])([a-z]?[0-9]+)(?P[,\\n\\t]*)(?P[0-9]+)([0-9]?)'matchobj.group(0)#'aa11123'matchobj.group(0,1,2)#('aa11123','a','a11')matchobj.group(0,'name1')#('aa11123','')matchobj.groupdict()#{'name1':'','name2':'123'}matchobj.groups()#('a','a11','','123','')matchobj[2]#'a11'matchobj['name2']#'123'#关于Match.start()、Match.end()、Match.span()matchobj.start()#0matchobj.end()#8matchobj.span()#(0,8)matchobj.start(2)#1matchobj.end(2)#4matchobj.span(2)#(1,4)matchobj.start('name2')#5matchobj.end('name2')#8matchobj.span('name2')#(5,8)再看一个没有分组的例子:nogroup_obj=re.match(r'.{3}','aa11123')ifnogroup_obj.lastindexisNone:print('yes')#yesnogroup_obj.group(0)#'aa1'nogroup_obj.groups()#()nogroup_obj.groupdict()#{}5.正则旗标Flags(RegexFlags)简写内联旗标描述re.ASCIIre.A(?a)使 \w, \W, \b, \B, \d, \D, \s 和 \S 执行仅限ASCII匹配而不是完整的Unicode匹配。Python3中 str 模式默认使用Unicode。re.IGNORECASEre.I(?i)执行忽略大小写的匹配。[A-Z]这样的表达式也将匹配小写字母。re.MULTILINEre.M(?m)使'^' 匹配字符串的开始和每一行的开头(紧随在换行符之后);使' 匹配字符串的末尾和每一行的末尾(紧接在换行符之前)。re.DOTALLre.S(?s)使 '.' 特殊字符匹配任意字符,包括换行符。re.UNICODEre.U(?u)在Python3中,str 模式默认将匹配Unicode字符。因此这个旗标无任何效果,仅保留用于向下兼容。re.VERBOSEre.X(?x)允许通过在视觉上分隔表达式的逻辑段落和添加注释来编写更为友好并更具可读性的正则表达式。表达式中的空白符会被忽略,除非是在字符类中,或前面有一个未转义的反斜杠,或者是在 *?, (?: 或 (?P 等形符之内。re.LOCALEre.L(?L)使 \w, \W, \b, \B 和忽略大小写的匹配依赖于当前语言区域。已不建议使用,请考虑改用Unicode匹配,语言区域机制不可靠。re.DEBUG无无显示有关被编译表达式的调试信息。re.NOFLAG无无表示未应用任何旗标,该值为 0。该旗标可被用作某个函数,关键字参数的默认值;或用作将与其他旗标进行有条件OR运算的基准值。具体使用方法,参见2.1,2.2,2.3,2.22。6.函数Functions6.1re.compile:将正则表达式编译为正则表达式对象,使用对象方法进行匹配(match()、search()等)。适用于需要多次使用某个正则表达式的场景,能让程序更高效。6.2re.findall:从左到右扫描string,返回所有与pattern匹配的结果,返回字符串列表或字符串元组列表(按照找到的顺序返回)。注意:如果没有组,返回与整个模式匹配的字符串列表;如果有且仅有一个组,返回与该组匹配的字符串列表;如果有多个组,返回与这些组匹配的字符串元组列表。re.findall('A+1+','AAA111A111AA111')#['AAA111','A111','AA111']re.findall('(A+)1+','AAA111A111AA111')#['AAA','A','AA']re.findall('(A+)(1+)','AAA111A111AA111')#[('AAA','111'),('A','111'),('AA','111')]6.3re.finditer:针对正则表达式 pattern 在 string 里的所有非重叠匹配返回一个产生 Match 对象的 iterator。 string 将被从左至右地扫描,并且匹配也将按被找到的顺序返回。空匹配也会被包括在结果中。foriteminre.finditer('A+1+','AAA111A111AA111'):print(item.group(0))#AAA111#A111#AA111re.findall('\s*','ABC')#['','','','']foriteminre.finditer('\s*','ABC'):print(item.group(0))print('*')在阅读6.4~6.6之前,建议简单浏览6.4 re.search:扫描整个string,找到与正则表达式 pattern匹配的第一个位置,返回相应的 Match对象,若没有与模式匹配的位置返回 None。6.5 re.match:从string起始位置开始匹配,能与pattern匹配则返回相应的 Match对象,否则返回 None。6.6 re.fullmatch:如果整个 string 与正则表达式 pattern 匹配,则返回相应的Match,如果字符串与模式不匹配则返回 None。re.match('abc\d','abc1').group(0)#'abc1're.fullmatch('abc\d','abc1').group(0)#'abc1'#re.fullmatch('abc\d','abc12').group(0)#报错6.7 re.sub:在字符串中进行正则表达式的替换操作,返回通过使用 repl 替换在 string 最左边非重叠出现的 pattern 而获得的字符串。如果样式没有找到,则不加改变地返回 string。 repl 可以是字符串或函数。repl 如果是字符串,其中任何反斜杠转义符号都会被处理,即 \n 会被转换为一个换行符,\r 会被转换为一个回车符;未知的ASCII字符转义序列会报错(保留,可能在未来会定义);其他未知转义序列例如 \& 会保持原样;向后引用,如 \6 对应样式中第6组所匹配到的子字符串,引用 \g 对应样式中命名为name的组合所匹配到的子字符串,\g 对应数字组,\g 就是 \2,\g0 就是 \20 ,组20。repl可以是一个函数,该函数接受单个Match对象作为参数,并返回替换字符串。count 表示最大替换个数,count 必须是非负整数。如果省略这个参数或设为0,所有的匹配都将会被替换。​​​​​1)repl为字符串re.sub(r'\sAND\s','&','BakedBeansAndSpam',flags=re.IGNORECASE)#'BakedBeans&Spam'#存在空匹配时:与前一个空匹配不相邻时发生替换re.sub('x*','-','abxd')#'-a-b--d-'print(re.sub('([a-z]\d)([A-Z]\s)',r'a1A\n','m2Ms4Z\tu9Z\n'))print(re.sub('([a-z]\d)([A-Z]\s)',r'a1A\1','m2Ms4Z\tu9Z\n'))print(re.sub('([a-z]\d)([A-Z]\s)','a1A\1','m2Ms4Z\tu9Z\n'))#python中\1这里没能显示#如果想表示字符\nprint(re.sub('([a-z]\d)([A-Z]\s)',r'a1A\\n','m2Ms4Z\tu9Z\n'))print(re.sub('([a-z]\d)([A-Z]\s)','a1A\\\\n','m2Ms4Z\tu9Z\n'))print('\d')#print(re.sub('([a-z]\d)([A-Z]\s)','a1A\d','m2Ms4Z\tu9Z\n'))#会报错再看一个有趣的例子(同 ),一个句子中可能有某些个单词重复打印,需要去掉这些多余的重复的单词,re.sub可以轻松的解决这个问题。需要注意的是,'?P='只能在同一正则表达式内部使用,在re.sub中引用pattern中的分组时,需要用'\g'。text='thethelittlecatcatisinthehathathat,welikeit.'re.sub(r'(\w+)((?:\s+\1)+)',r'\1',text)#'thelittlecatisinthehat,welikeit.'re.sub(r'(\w+)((?:\s+\1)+)',r'\g',text)#'thelittlecatisinthehat,welikeit.'re.sub(r'(?P\w+)((?:\s+\1)+)',r'\g',text)#'thelittlecatisinthehat,welikeit.'2)repl为函数deffunc1(matchobj):print(matchobj.group(0))ifmatchobj.group(0)=='-':return''else:return'-'re.sub('-{1,2}',func1,'pro----gram-files')#--#--#-#'pro--gramfiles're.sub('\d',func1,'pro----gram-files')#返回原字符串#'pro----gram-files'问题:已知一个字符串sentence和一个整数discount,要求对句子中每个表示价格的单词($+数值),计算此价格的基础上减免discount% 的折后价并更新到句子中,更新后的价格应该表示为一个恰好保留小数点后两位的数字。使用re.sub解决:importredefdiscountPrices(sentence,discount):deff(match):v=match.group(1)returnf'${float(v)*(100-discount)/100:.2f}'returnre.sub(r'(??
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 会员注册

本版积分规则

QQ|手机版|心飞设计-版权所有:微度网络信息技术服务中心 ( 鲁ICP备17032091号-12 )|网站地图

GMT+8, 2025-1-10 19:01 , Processed in 0.845171 second(s), 25 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表