您所在的位置:小祥子 » 编程 » Python » 正文

15 正则表达式

时间:2015-08-18 编辑:《Python 核心编程》 来源:CnBlogs
?? 引言/动机 ?? 特别的字符和符号 ?? 正则表达式与 Python ?? re 模块 15.1 介绍/动机         正则表达式(RE)为高级文本模式匹配,以及搜索-替代等功能提供了基础。     正则表达式(RE)是一 些由字符和特殊符号组成的字符串,它们描述了这些字符和字符的某种重复方式。     正则表达式(RE)能按某种模式匹配一个有相似特征的字符串的集合。     正则表达式(RE)能按某模式匹配一系列有相似特征的字符串。     Python 通过标准库的re 模块支持正则表达式(RE)。         核心笔记:查找与匹配的比较         本章通篇涉及到对查找和匹配用法的讲述。当我们完全讨论与字符串中模式有关的正则表达式     时,我们会用术语 “matching”(“匹配”),指的是术语pattern-matching(模式匹配)。在Python     专门术语中,有两种主要方法完成模式匹配:搜索(searching)匹配(matching)。搜索,即在字符     串任意部分中查找匹配的模式,而匹配是指,判断一个字符串能否从起始处全部或部分的匹配某个     模式。搜索通过search()函数或方法来实现,而匹配是以调用match()函数或方法实现的。         总之,当我们说模式的时候,我们全部使用术语“matching”(“匹配”);我们按照Python 如     何完成模式匹配的方式来区分“搜索”和“匹配”。 您的第一个正则表达式     RE Pattern        String(s) Matched     foo                    foo     Python              Python     abc123              abc123     上表中第一个正则表达式模式是"foo"。这个模式不包含任何特殊符号去匹配其他符号,它仅匹配自身所描述的,所以只有字符串"foo"匹配此模式。同理,“Python”和“abc123.”也一样。     正则表达式的强大之处在于特殊符号的应用,特殊符号定义了字符集合,子组匹配,模式重复次数,正是这些特殊符号使得一个正则表达式可以匹配字符串集合而不只是一个字符串。 正则表达式使用的特殊符号和字符                 用管道符号( | )匹配多个正则表达式模式         管道符号( | ), 就是您键盘上的竖杠,表示一个或操作,它的意思是选择被管道符号分隔的 多个不同的正则表达式中的一个。            匹配任意一个单个的字符( . )         点字符或句号(.)符号匹配除换行符(NEWLINE)外的任意一个单个字符(Python 的正则表达式有     一个编译标识 [S or DOTALL],该标识能 去掉 这一限制,使 ( . ) 在匹配时包括换行符(NEWLINEs)。)     (这里括号缺一半) 无论是字母、数字、不包括“\n”的空白符、可打印的字符、还是非打印字符,     或是一个符号,“点”,( . )都可以匹配他们。        从字符串的开头或结尾或单词边界开始匹配( ^/$ /\b /\B )         还有些符号和特殊字符是用来从字符串的开头或结尾开始搜索正则表达式模式的。如果想从字     符串的开头开始匹配一个模式,你必须用脱字符号( ^ , 即,Caret)或特殊字符 \A (大写字母A 前     面加上一个反斜线). 后者主要是为那些没有caret 符号的键盘使用的,比如说国际键盘。类似,美     元符号 ( $ ) 或 \Z 是用来(零宽度)匹配字符串的结尾的。            特殊字符 \b and \B 用来匹配单词边界。两者之间的区别是,\b 匹配的模式是一个单词边界,     就是说,与之对应的模式一定在一个单词的开头,不论这个单词的前面是有字符(该词在一个字符串     的中间),还是没有字符(该单词在一行的起始处)。同样地,\B 只匹配出现在一个单词中间的模式(即,     不在单词边界上的字符)。        创建字符类( [ ] )         尽管点号可用来匹配任意字符,但有时候你需要匹配某些个特殊的字符。正因为如此,方括号 ( [ ] )被发明出来。使用方括号的正则表达式会匹配方括号里的任何一个字符。            对仅有单个字符的正则表达式 ,使用管道符号和方括号的效果是等价的。             [aeiou] == (a|e|i|o|u)     指定范围 ( - ) 和 否定( ^ )         方括号除匹配单个字符外,还可以支持所指定的字符范围。方括号里一对符号中间的连字符(-)      用来表示一个字符的范围,例如,A–Z, a–z, 或 0–9 分别代表大写字母、小写字母和十进制数     字。这是一个按字母顺序排序的范围,所以它不限于只用在字母和十进制数字上。另外,如果在左      方括号后第一个字符是上箭头符号(^),就表示不匹配指定字符集里的任意字符。        使用闭包操作符 ( *, +, ?, {} ) 实现多次出现/重复匹配         零次或零次以上的情况(在计算机语言和编译器原理里,此操作符被叫做 Kleene 闭包操作符)。         花括号操作符({ })             花括号里可以是单个的值,也可以是由逗号分开的一对值。             如果是 一个值,如,{N},则表示匹配N 次出现;如果是一对值,即,{M, N},就表示匹配M 次到N 次出现。         问号有两种含义(被重载):             1. 单独使用时表示匹配出现零次或一次的情况             2. 紧跟在表示重复的元字符后面时,表示要求搜索引擎匹配的字符串越短越好。例如:(+?)         贪心             当使用了表示重复的元字符(*+?{m,n})时,正则表达式 引擎在匹配模式时会尽量"吸收"更多的字符,这就叫做"贪心"。             问号告诉正则表达式引擎尽可能地偷懒,要求当前匹配消耗的字符越少越好,留下尽可能多的字符给后面的模式(如果存在)。            特殊字符表示字符集         我们还提到有一些特殊字符可以用来代表字符集合。例如,你可以不使用 “0–9”这个范围     表示十进制数字,而改用简写“\d”表示。另一个特殊的字符 “\w” 可用来表示整个字符数字的     字符集,即相当于“A-Za-z0-9_”的简写形式,特殊字符“\s” 代表空白字符。这些特殊字符的大     写形式表示不匹配,比如,“\D” 表示非十进制数字的字符(等价于 “[^0-9]”),等等。            用圆括号(()) 组建组         一对圆括号(()) 和正则表达式一起使用时可以实现以下任意一个(或两个)功能:             ?? 对正则表达式进行分组             ?? 匹配子组 15.3 正则表达式和Python 语言     re 模块在Python1.5 版本被引入。如果你正在使用Python 的早期版本, 你将只能用已过时的regex、regsub 模块。     regex 和regsub 这两个模块已在Python 2.5 版本时被移除了,在 Python2.5 及 其后续版本,引入这两个模块中的任何一个将会引发Import Error 异常。      新的re 模块支持功能更强大、更通用的Perl 风格(具 体说是Perl5 的风格)的正则表达式,允许多线程共享同一经过编译的正则表达式对象,同时它还支持对正则表达式分组进行命名和按名字调用。     re 引擎已在Python1.6 版本中被重写,改进了它的性能并添加了对Unicode 的支持。     新的re 引擎,内部被叫做sre, 替代了1.5 版本中内部名为pcre 的re 引擎。 re 模块: 核心函数和方法                                                        使用compile()编译正则表达式     编译regex 对象时给出一些可选标志符,可以得到特殊的编译对象。这些对象将允许不区别大小 写的匹配,或使用系统的本地设置定义的字母表进行匹配等。     regex 对象还有一些数据属性,其中两个是创建时给定的编译标志符和正则表达式模式。 匹配对象 和 group(), groups() 方法     在处理正则表达式时,除regex 对象外,还有另一种对象类型 - 匹配对象。这些对象是在match() 或search()被成功调用之后所返回的结果。     匹配对象有两个主要方法:group() 和 groups().         group()方法或者返回所有匹配对象或是根据要求返回某个特定子组。         groups()则很简单,它返 回一个包含唯一或所有子组的元组。         如果正则表达式中没有子组的话, groups() 将返回一个空元组,而group()仍会返回全部匹配对象。         Python 语言中的正则表达式支持对匹配对象进行命名的功能. 用match()匹配字符串     match()函 数尝试从字符串的开头开始对模式进行匹配。         如果匹配成功,就返回一个匹配对象,而如果匹配失败了,就返回None。         匹配对象的group() 方法可以用来显示那个成功的匹配。         >>> import re         >>> rex = re.compile('foo')         >>> m = rex.match('food on the table.')         >>> m.group()         'foo'         >>>
search() 在一个字符串中查找一个模式 (搜索与匹配的比较)     其实,你要搜索的模式出现在一个字符串中间的机率要比出现在字符串开头的机率更大一些。这正是search()派上用场的时候。     search 和match 的工作方式一样,不同之处在于search 会检查参数字符串任意位置的地方给定正则表达式模式的匹配情况。如果搜索到成功的匹配,会返回一个匹配对象,否则返回None。         >>> re.match('foo', 'seafood') # no match         >>> re.search('foo', 'seafood') # use search() instead         <_sre.SRE_Match object at 0x000000000252D8B8>         >>> 匹配多个字符串( | )   匹配任意单个字符( . )   创建字符集合( [ ] )   重复、特殊字符和子组     正则表达式中最常见的情况包括特殊字符的使用,正则表达式模式的重复出现,以及使用圆括号对匹配模式的各部分进行分组和提取操作。 从字符串的开头或结尾匹配及在单词边界上的匹配(^, $, \b)
用findall()找到每个出现的匹配部分         findall()自Python1.5.2 版本被引入。它用于非重叠地查找某字符串中一个正则表达式模式出     现的情况。findall()和search()相似之处在于二者都执行字符串搜索,但findall()和match()与     search()不同之处是,findall()总返回一个列表。如果findall()没有找到匹配的部分,会返回空     列表;如果成功找到匹配部分,则返回所有匹配部分的列表(按从左到右出现的顺序排列)。            包含子组的搜索会返回更复杂的一个列表,这样做是有意义的,因为子组是允许你从单个正则     表达式中抽取特定模式的一种机制,正则表达式仅有一个子组时,findall()返回子组匹配的字符串     组成的列表;如果表达式有多个子组,返回的结果是一个元组的列表,元组中每个元素都是一个     子组的匹配内容,像这样的元组(每一个成功的匹配对应一个元组)构成了返回列表中的元素。 用sub()[和 subn()]进行搜索和替换 sub()和subn()两种函数/方法用于完成搜索和代替的功能,都是将某字符串中所有匹配正则表达式模式的部分进行替换。 用来替换的部分通常是一个字符串,但也可能是一个函数,该函数返回一个用来替换的字符串。 subn()和sub()一样,但它还返回一个表示替换次数的数字,替换后的字符串和表示替换次数的数字作为一个元组的元素返回。     >>> rex = re.compile('o')     >>> rex.sub('O','foo')     'fOO'     >>> rex.subn('O','foo')     ('fOO', 2)     >>> 用split()分割(分隔模式)         re 模块和正则表达式对象的方法split()与字符串的split()方法相似,前者是根据正则表达式     模式分隔字符串,后者是根据固定的字符串分割,因此与后者相比,显著提升了字符分割的能力。如     果你不想在每个模式匹配的地方都分割字符串,你可以通过设定一个值参数(非零)来指定分割的最     大次数。     如果分隔符没有使用由特殊符号表示的正则表达式来匹配多个模式,那re.split()和 string.split()的执行过程是一样的。     核心笔记 : Python 原始字符串(raw strings)的用法         你可能已经看到前面关于原始字符串用法的一些例子了。原始字符串的产生正是由于有正则表     达式的存在。原因是ASCII 字符和正则表达式特殊字符间所产生的冲突。比如,特殊符号“\b”在     ASCII 字符中代表退格键,但同时“\b”也是一个正则表达式的特殊符号,代表“匹配一个单词边界”。     为了让RE 编译器把两个字符“\b”当成你想要表达的字符串,而不是一个退格键,你需要用另一个     反斜线对它进行转义,即可以这样写:“\\b”。         但这样做会把问题复杂化,特别是当你的正则表达式字符串里有很多特殊字符时,就更容     易令人困惑了。我们曾介绍过原始字符串,经常被用于简化正则表达式的复杂程度。     事实上,很多Python 程序员在定义正则表达式时都只使用原始字符串。    特别推荐: 正则表达式30分钟入门教程