当前位置: 首页 > 后端技术 > Python

python中字符串与正则表达式全解

时间:2023-03-26 00:33:41 Python

一、转义字符正则表达式是基于字符串的。当字符中需要使用特殊字符时,python使用反斜杠对字符进行转义。下表:转义符说明\(行尾)续行符\\反斜杠符号\'单引号\"双引号\a响铃\b退格(Backspace)\e转义\000空\n行feed\v垂直制表符\t水平制表符\r回车\f换页\oyy八进制数yy表示的字符,例如:\o12表示换行\xyy十进制数yy表示的字符,对于例:\x0a代表换行符\other其他字符以正常格式输出,例如:\w就是\w,\.就是\.原始字符串有时候我们不想让转义字符生效,我们只想显示字符串的本义,这个需要用r和R来定义原来的字符串。例如:print(r'\t\r')实际输出的是“\t\r”。二、理解正则表达式正则表达式是字符串操作的一部分逻辑公式是使用一些预先定义好的特定字符他将这些特定字符组合起来形成一个“规则字符串”。这个“规则字符串”用来表达一个字符串的过滤逻辑。正则表达式是一个非常强大的字符串匹配工具。在其他编程语言中也有正则表达式的概念。蟒蛇也不例外。使用正则表达式,我们想从返回的页面内容中提取出我们想要的内容很容易。一个正则表达式的一般匹配过程是:1.取出表达式,依次与文本中的字符进行比较。2、如果每个字符都能匹配,则匹配成功;一旦有匹配失败的字符,则匹配失败。3.如果表达式中有量词或边界,过程略有不同。下图显示了使用正则表达式进行匹配的过程:3.正则表达式的语法规则具有非贪婪模式的正则表达式常用于在文本中查找匹配字符串。Python中的量词默认是贪婪的(或者在一些语言中默认是非贪婪的),总是试图匹配尽可能多的字符;非贪婪则相反,总是试图匹配尽可能少的字符。例如:如果使用正则表达式“ab”来查找“abbbc”,它将查找“abbb”。而如果非贪婪量词“ab?”使用时,将找到“a”。注意:我们一般采用非贪心模式来提取。2.反斜杠问题和大多数编程语言一样。""在正则表达式中用作转义字符,可能会导致反斜杠问题。如果需要匹配文本中的字符“”,则在编程语言表达的正则表达式中需要4个反斜杠“\”:前两个和后两个在编程语言中用于转义成反斜杠斜杠,转换为两个反斜杠,然后在正则表达式中转义为一个反斜杠。Python中的原生字符串很好地解决了这个问题,本例中的正则表达式可以用r""表示。同样,匹配数字的“d”可以写成r“d”。有了原生字符串,妈妈们再也不用担心漏掉反斜杠了,写出来的表达方式更直观。这里要注意区分正则表达式中的转义和字符串中的转义。因为正则表达式是一个字符串,它首先将代码中写的格式转换为系统可以识别的字符串(在字符串中使用转义),然后将系统识别的字符串转换为系统可以识别的正则对象(在正则表达式中使用转义)。并且字符串中的转义可以被正则表达式识别,但正则表达式中的转义字符串可能无法识别。例如:.n只能识别字符串中的n,不能。它可以识别两者。andn在常规代码示例中importretext='.525heart.com\n'#在系统中表示为.525heart。comnewlinepatternstr='\.525heart.com\n'#代码写成\.525heart.com\n#系统识别为\.525heart.com换行串转义可以识别\n,不能识别\.原样保存#正则识别为.525heart任何字符com换行正则转义都可以识别\。and.patternstr=r'\.525heart.com\n'#代码中写的是\.525heart.com\n#系统识别的字符串是\.525heart.com\n原样保存result=re.search(pattern,text)print(result.group())输出结果为\.525heart.com\n.525heart.com5.PythonRe模块Python自带re模块,提供正则表达式样式支持。下面列出主要使用的方法#返回模式对象re.compile(string[,flag])#下面是用于匹配的函数re.match(pattern,string[,flags])re.search(pattern,string[,标志])re.split(模式,字符串[,maxsplit])re.findall(模式,字符串[,标志])re.finditer(模式,字符串[,标志])re.sub(模式,repl,字符串[,count])re.subn(pattern,repl,string[,count])在介绍这些方法之前,我们先介绍一下pattern的概念。Pattern可以理解为一个匹配模式,那么我们如何得到这个匹配模式呢?很简单,我们需要用到re.compile方法。比如pattern=re.compile(r'hello'),我们在参数中传入一个原生的字符串对象,通过compile方法编译生成一个pattern对象,然后我们使用这个对象进行进一步的匹配。另外,大家可能注意到了另一个参数flags,这里解释一下这个参数的含义。参数flag为匹配模式的值,按位或'|'可以用来表示同时有效,比如re.I|re.M.可选值有:re.I(全拼:IGNORECASE):忽略大小写(括号内全拼,下同)re.M(全拼:MULTILINE):多行模式,改变'^'和'$'行为(见上图)re.S(全拼:DOTALL):点击任意匹配模式,使'.'可以匹配包括n在内的所有字符re.L(全拼:LOCALE):制定预定字符类wWbBsS取决于当前locale设置re.U(全拼:UNICODE):制定预定字符类wWbBsSdD取决于unicodere.X(全拼:VERBOSE)定义的字符属性:详细模型。在这种模式下,正则表达式可以是多行的,忽略空白字符,可以添加注释。flags参数可以放在compile中,用于编译正则表达式字符串。如:pattern=re.compile('.*525heart.*',re.S)也可以放在匹配查询函数中编译正则表达式字符串,如:result=re.search('.*525heart.*',text,re.S)但是,它只能用来帮助编译正则表达式字符串和生成正则对象,而不能处理正则对象。如下图是错误的。pattern=re.compile('.*525heart.*')result=re.search(pattern,text,re.S)6.正则方法我们需要在刚刚提到的其他方法中使用re.match现在我们已经达到这个模式了,下面一一介绍。注:以下7个方法中的flags也代表了匹配模式的含义。如果在生成模式时已经指定了flags,那么后面的方法就不需要传入这个参数了。1.re.match(pattern,string[,flags])这个方法会从字符串的开头(我们要匹配的字符串)开始,尝试匹配pattern,向后匹配。如果遇到无法匹配的字符,立即返回None,如果匹配到字符串末尾则返回None。两种结果都表示匹配失败,否则匹配模式成功,同时结束匹配,不会向后匹配字符串。我们通过一个例子来理解#importremoduleimportre#将正则表达式编译成Pattern对象,注意hello前面的r表示“原生字符串”pattern=re.compile(r'hello')#使用re.match匹配文本,得到匹配结果。如果没有匹配,它将返回Noneresult1=re.match(pattern,'hello')result2=re.match(pattern,'helloworld!')result3=re.match(pattern,'heloworld!')result4=re.match(pattern,'helloworld!')#If1匹配成功ifresult1:#使用Match获取组信息print(result1.group())else:print('1matchFailed!')#if2匹配成功ifresult2:#使用Match获取组信息print(result2.group())else:print('2匹配失败!')#if3匹配成功ifresult3:#使用Match获取组信息print(result3.group())else:print('3匹配失败!')#if4匹配成功ifresult4:#使用Match获取组信息print(result4.group())else:print('4匹配失败!')运行结果hellohello3匹配失败!hello匹配分析:第一次匹配,pattern正则表达式为'hello',我们匹配的目标字符串也是hello,从头到尾完全匹配,匹配成功。对于第二场比赛,字符串是helloworld。从字符串开头的匹配模式可以完全匹配。当模式匹配结束时,匹配也同时结束。后续oworld不再匹配,返回匹配成功信息。第三次匹配,字符串为heloworld,从字符串开头开始匹配模式,发现'o'时无法完成匹配,终止匹配,返回None第四次匹配与第二次相同匹配原则,即使遇到空格字符也不受影响。我们还看到result.group()最后被打印出来了。这是什么意思?下面说一下Match对象的属性和方法。re.match函数返回一个Match对象。Match对象是匹配的结果,包含了很多关于匹配的信息,这些信息可以通过Match提供的可读属性或方法来获取。属性:string:匹配时使用的文本。re:匹配时使用的模式对象。pos:正则表达式开始搜索的文本中的索引。该值与Pattern.match()和Pattern.seach()方法的同名参数相同。endpos:正则表达式结束搜索的文本中的索引。该值与Pattern.match()和Pattern.seach()方法的同名参数相同。lastindex:最后捕获的组在文本中的索引。如果没有捕获数据包,则为None。lastgroup:最后捕获组的别名。如果该组没有别名或没有捕获的组,则将为None。方法:group([group1,…]):获取group截取的一个或多个字符串;当指定多个参数时,将以元组的形式返回。group1可以使用数字或别名;数字0代表整个匹配的子串;如果没有填写参数,则返回group(0);对于没有截获字符串的组返回None;返回已拦截多次字符串的组的最后拦截的子字符串。groups([default]):以元组的形式返回所有组截取的字符串。相当于呼叫组(1,2,...最后)。default表示不截取字符串的组用这个值代替,默认是None。groupdict([default]):返回一个字典,其key为有别名的group的别名,group截取的子串为value。不包括没有别名的组。default含义同上。start([group]):返回string中指定group截取的子串的起始索引(子串第一个字符的索引)。group默认值为0。end([group]):返回string中指定group截取的子串的结束索引(子串最后一个字符的索引+1)。group的默认值为0。span([group]):返回(start(group),end(group))。expand(template):将匹配到的组代入模板并返回。模板可以使用id或者g,g来指代组,但是不能使用数字0。id和g是等价的;但是10会被认为是第10个分组,如果要在1后面表示字符'0',只能用g0。下面用一个例子来体验一下:#一个简单的匹配例子importre#匹配如下内容:word+space+word+任意字符m=re.match(r'(\w+)(\w+)(?P.*)','helloworld!')print("m.string:",m.string)print("m.re:",m.re)print("m.pos:",m.pos)print("m.endpos:",m.endpos)print("m.lastindex:",m.lastindex)print("m.lastgroup:",m.lastgroup)print("m.group():",m.group())print("m.group(1,2):",m.group(1,2))print("m.groups():",m.groups())打印("m.groupdict():",m.groupdict())print("m.start(2):",m.start(2))print("m.end(2):",m.end(2))print("m.span(2):",m.span(2))print(r"m.expand(r'\g\g\g'):",m.expand(r'\2\1\3'))输出为m.string:helloworld!m.re:re.compile('(\\w+)(\\w+)(?P.*)')m.pos:0m.endpos:12m.lastindex:3m.lastgroup:signm.group():helloworld!m.group(1,2):('hello','world')m.groups():('你好','world','!')m.groupdict():{'sign':'!'}m.start(2):6m.end(2):11m.span(2):(6,11)m.expand(r'\g\g\g'):世界你好!2、re.search(pattern,string[,flags])search方法和match方法很相似,不同的是match()函数只检测字符串开头是否匹配到re。search()将扫描整个字符串以找到匹配项。match()只有在0位置匹配成功才会返回,如果在开始位置匹配不成功,match()和返回None一样,搜索方法的返回对象也是matches()返回的方法和属性的对象。举个例子感受一下#importremoduleimportre#将正则表达式编译成Pattern对象pattern=re.compile(r'world')#使用search()查找匹配的子串,没有匹配的子串String会返回None#本例中使用match()无法匹配成功match=re.search(pattern,'helloworld!')ifmatch:#使用Match获取组信息print(match.group())outputisworld3,re.split(pattern,string[,maxsplit])根据匹配的子串对字符串进行分割,返回列表。maxsplit用于指定最大拆分数,不指定则全部拆分。我们通过下面的例子来感受一下。importrepattern=re.compile(r'\d+')print(re.split(pattern,'one1two2three3four4'))输出为['one','two','three','four','']4。re.findall(pattern,string[,flags])搜索字符串并以列表形式返回所有匹配的子字符串。我们用这个例子感受一下importrepattern=re.compile(r'\d+')print(re.findall(pattern,'one1two2three3four4'))output['1','2','3','4']5。re.finditer(pattern,string[,flags])搜索字符串并返回一个迭代器,该迭代器顺序访问每个匹配结果(匹配对象)。我们通过下面的例子感受一下importrepattern=re.compile(r'\d+')forminre.finditer(pattern,'one1two2three3four4'):print(m.group(),end='')的输出结果为12346.re.sub(pattern,repl,string[,count])使用repl替换string中每个匹配的子字符串并返回替换后的字符串。当repl是一个字符串时,可以用id或者g,g来指代组,但不能用数字0。当repl是一个方法时,该方法应该只接受一个参数(Match对象)并返回一个字符串用于替换(不能在返回的字符串中引用组)。count用于指定最大替换次数,不指定则全部替换。importrepattern=re.compile(r'(\w+)(\w+)')s='isay,helloworld!'print(re.sub(pattern,r'\2\1',s))deffunc(m):returnm.group(1).title()+''+m.group(2).title()print(re.sub(pattern,func,s))输出是说我,世界你好!我说,世界您好!7.re.subn(pattern,repl,string[,count])返回(sub(repl,string[,count]),替换次数)。importrepattern=re.compile(r'(\w+)(\w+)')s='isay,helloworld!'print(re.subn(pattern,r'\2\1',s))deffunc(m):returnm.group(1).title()+''+m.group(2).title()print(re.subn(pattern,func,s))输出为('sayi,worldhello!',2)('ISay,HelloWorld!',2)8.PythonRe模块的另一种使用方式上面我们介绍了匹配、搜索等7个工具方法。等等,但是调用方法是re.match和re.search。其实还有一个调用方法,可以通过pattern.match和pattern.search来调用,这样调用就不需要将pattern作为第一个参数。你可以随心所欲地称呼它。函数API列表match(string[,pos[,endpos]])|re.match(pattern,string[,flags])search(string[,pos[,endpos]])|re.search(pattern,string[,flags])split(string[,maxsplit])|re.split(pattern,string[,maxsplit])findall(string[,pos[,endpos]])|re.findall(pattern,string[,flags])finditer(string[,pos[,endpos]])|re.finditer(pattern,string[,flags])sub(repl,string[,count])|re.sub(pattern,repl,string[,count])subn(repl,string[,count])|re.sub(pattern,repl,string[,count])