Python基础——windows自动化篇(九)-正则表达式

正则表达式(regexp)

正则表达式在某种意义上可以算是字符串操作中的最高级别了,并不是因为它的语法的复杂,而是它的灵活。理解这一点就需要了解正则表达式的本质,无论多么复杂的正则表达式,它的本质就是字符串,目的就是用来记录其他字符串的规律。看似有些抽象,但是其实很容易理解,大多数人在使用dos命令的时候,会使用到通配符,比如在某个目录列出所有的pdf文档,方法就是dir *.pdf——这里的*表示统配,也就是可以代表任何字符串,这个命令也就是列出来所有符合以下命名的文件:任意字符串+”.pdf”后缀;doc和excel文档中的一些替换规则和格式化规则也涉及到这种简单的正则统配。我们所说的正则,其实就是类似的东西,更为复杂的字符串匹配规则——除非你需要匹配的字符串规则很容易。在Linux平台上,正则表达式是必须的,很多命令都基于正则表达式,如果没有这套高效的字符串匹配逻辑,那么对于使用者是很悲惨的。

讨论Python正则模块之前,必须要把正则表达式本身讨论清楚——事实上深刻理解了正则表达式,python中的使用就容易多了,不过不要妄想一次就可以把正则表达式都理解了,这是不可能的,就算是天才也需要实际的操作才能真正的学会。我不否定世界上有很多天才,但是我始终建议学习正则表达式,最少要学习3遍。完成这部分学习,并不是期望成为正则高手,这并不是这部分学习的目的,而且高手不是看教材就能学习出来的。这部分学习后,希望能够“入门”。遇到问题知道以一种什么样的思路进行思考,需要帮助的时候知道如何去查询相关的资料,这就足够了。我自己每次用到正则也是随查随用,很少做相关的事情,好在正则的相关资料网上多的出奇,足够一个菜鸟成为正则高手了。下面开始进入正则表达式的介绍和讨论。

在python中,正则表达式的模块是re,我们的讨论过程会使用这个模块举例子进行测试,另外,一些在线的正则表达式测试也可以进行测试,比如js的正则表达式测试网站:http://regexpal.com/

字符

这里的字符和字符串中的字符是一样的,大多数字符匹配它本身,除了一些元字符,我们可以简单的认为元字符,就是正则语法中的一些关键字,它们有特殊的含义,有的表示特殊的匹配,有的表示其他的语法规则。简单的字符匹配如下:

Re的基本使用很简单,指定正则表达式匹配字符串,编译,匹配。Re.match方法如果匹配到,则返回一个匹配对象,如果没有匹配到,则返回空。我们可以看到,正则表达式’abc’可以匹配到它本身。事实上除了元字符,其他字符都是匹配它本身的。

元字符

正则中的元字符包括很多,具体可以见链接:http://msdn.microsoft.com/zh-cn/library/ae5bf541(v=vs.80).aspx

元字符中的特殊字符包括:.^$*+?{[]\|()

在正则的语法中,它们有其他的含义和作用——一些是单独使用的,一些是组合使用的。我们先来看其中最常用的一个——[],它表示字符的集合。

字符集

包含在[]中的字符集合,有两个作用,一个是用来匹配范围,这里的范围是指,匹配到属于这个范围的任意一个字符;另一个,是包含某些元字符——大部分元字符在[]中会失去本身的特殊含义,成为普通的字符,除了^[]\这四个字符,因为他们是字符集语法。

其中,^放在[]的开头,表示取反,表示和[]中的字符集都不匹配,放在[]中间,就和其他元字符一样了,表示匹配它本身。简单的例子,[^abcd]表示匹配除abcd以外的任何字符。

在字符集中,逐一枚举是这样的方式当然是有解决方案的,可以用-来表示范围,比如[0-9]匹配0到9的数字,[a-zA-Z]匹配所有的字符。

\在正则中有两个作用,第一个是转义,第二个是特殊匹配。

转义字符

像上面讨论过的,一些元字符并不匹配他们本身,那么如何匹配这些元字符呢?在它们前面加上\进行转义就可以了。这和字符串中的路径是一样的,需要用\转义。所有在正则表达式中的带有特殊含义的字符,都需要\进行转义去匹配它们本身。当然,就像之前路径中转义的\一样,我们同样可以在字符串前加一个r来表示原始字符串,不然如果想要匹配\本身,需要’\\\\’这样麻烦的正则表达式,但是可以直接使用r’\’来表示。

特殊匹配

特殊匹配包括一些用\表示的,和一些其他特殊的字符。常用的有下面这些:

******************************************************************************


x|y


匹配 x 或 y(分支语句)。例如,‘z|food‘ 匹配“z”或“food”。‘(z|f)ood‘ 匹配“zood”或“food”


\b


匹配一个字边界(开始或结束),例如,“er\b”匹配“never”中的“er”,但不匹配“verb”中的“er”, “\ber\b”匹配”er”


\B


非字边界匹配,和\b相反。“er\B”匹配“verb”中的“er”,但不匹配“never”中的“er”。


\d


数字字符匹配。等效于 [0-9]


\D


非数字字符匹配。等效于 [^0-9]


\n


换行符匹配。等效于 \x0a 和 \cJ


\s


匹配任何空白字符,包括空格、制表符、换页符等。与 [ \f\n\r\t\v] 等效


\S


匹配任何非空白字符。与 [^ \f\n\r\t\v] 等效


\t


制表符匹配。与 \x09 和 \cI 等效


\w


匹配任何字类字符,包括下划线。与“[A-Za-z0-9_]”等效


\W


与任何非单词字符匹配。与“[^A-Za-z0-9_]”等效


.


匹配出换行\n之外的任何字符,等价于[^\n]


^


在字符集之外,匹配字符串的开始*


$


在字符集之外,匹配字符串的结束*

*:其中,^和$用于完全匹配的情况,各自匹配开始和结束,如果整体的完全匹配可以使用^pattern$的格式,如完全匹配123,写成^123$。
******************************************************************************

重复

到此为止,正则表达式中的基本元素几乎都已经简单讨论过了,基本的语法元素中,还有一个重要的部分,就是重复。既然正则表达式是用来记录字符串规则的,那么重复的规则,在字符串中简直是比比皆是。比如电话号码或者QQ号码,就是数字的重复,单词就是字母的重复,还有更多重复的组合等等。正则表达式中,重复的语法包括下面几种:


*


重复零次或者多次,次数不限


+


重复一次或者更多次



重复0次或者1次


{n}


重复n次


{n,}


重复n次或者更多次


{n,m}


重复n到m次


?


当此字符紧随任何其他限定符(*、+、?、{n}、{n,}、{n,m})之后时,匹配模式是“非贪心的”。“非贪心的”模式匹配搜索到的、尽可能短的字符串,而默认的“贪心的”模式匹配搜索到的、尽可能长的字符串。

最后一个需要解释一下,正则表达式在默认情况下,有一种贪婪原则,也就是尽可能的去匹配长的字符串。比如,在字符串“aaaa”中,“a+?”只匹配单个“a”,而“a+”匹配所有“a”,也就是”aaaa”。这种情况出现在重复中,在重复的标识符后加上一个?,就代表了非贪婪匹配,匹配到最短的字符串。可以简单的写代码如下:

Re模块处理基本正则

基本的正则表达式语法都已经讨论过了,灵活运用这些语法,可以完成大部分一般的匹配操作。下面用一些简单的例子来讨论re模块的使用,并熟悉上面已经讨论过的这些基本的正则语法。之后,会讨论一些正则表达式的高级操作。

和之前讨论过的思路一样,re模块进行字符串匹配,大体还是3个步骤:

  1. 用re.compile得到一个编译过的pattern object,支持两个参数,一个是正则表达式,是必须的,第二个是flag,默认为0,其他支持的flag包括:

Re.S           DOTALL             表示.匹配任意字符,不包括\n

Re.I           IGNORECASE   表示忽略大小写

Re.L           LOCALES           表示让\w,\W,\b,\B和当前locale一致

Re.M         MULTILINE       表示多行匹配模式,只影响^和$

Re.X          VERBOSE          表示verbose模式,增加正则表达式的可读性

  1. 使用pattern object的各种方法进行对匹配字符串的操作;
  2. 如果pattern object的方法返回match object对象,可以从中得到匹配字符串信息;

Parren object 常用的方法包括match,search,findall,其中match是从字符串开始处进行匹配,seach是扫描整体字符串找到第一个匹配,findall用来搜索字符串中所有匹配的内容,并以元组返回。

Parren object 常用的正则方法包括match,search,sub和findall(或finditer),其中match是从字符串开始处进行匹配,seach是扫描整体字符串找到第一个匹配,findall用来搜索字符串中所有匹配的内容,并以元组返回。注意正则方法只是对parrent object而言,还有一种叫做匹配方法,是对已经匹配到的对象而言,即对match object而言。

下面是这些常用的正则方法的示例:

Match(str,[pos,[endpos]]):
匹配方法,给定匹配区间,注意正则的贪心问题,示例如下:

Search(str,[pos,[endpos]]): 搜索方法,给定匹配区间内返回到第一个搜到的值位置,使用方法和match相当,但是并不是从第一位开始,这点和match不同,示例如下:

sub(repl, string[, count = 0]) --> newstring:用来查找和替换,用指定的字符串替换被匹配到的字符串,subn将新的字符串和被替换的数量以元组方式返回,如下:

findall(string[, pos[, endpos]]) --> list:查找方法,给定匹配区间内查找所有匹配的集合并返回。如下:

Finditer返回一个interator来遍历所有的match object:

Match object 常用的方法包括start,end,span,group,分别用来表示匹配区域的开始位,结束位,区间和匹配字符串;常用属性有pos,endpos,string和re,分别表示pattern object的开始位,结束位,被匹配的字符串和匹配对象,即match(str,[pos,[endpos]])中的pos,endpos,string和patter object实例本身,它们的示例如下:

常用方法:

常用属性:

正则表达式高级
分组

分组的出现最早是为了解决正则中的重复问题,单个字符的重复可以直接在字符后加上限定,多字符的重复就需要分组了;当然一个正则中可以出现多个分组,我们可以将它称之为子表达式。分组在实际应用中作用比较大,网络上一个比较常用的示例就是IP地址的匹配,一个最粗糙的就是(\d{1,3}\.){3}\d{1,3},匹配四个三位数字,中间用.分开,这就是分组的最简单的应用。当然IP地址的正则并不是这么去匹配和计算的,由于正则表达式本身不能去进行数字的计算,所以IP地址的匹配稍微麻烦一些,不过这种常用的很容易查到,((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)。

Python中处理分组使用match对象中的group()方法,一个简单的示例如下,取出一个简易的存货信息中的匹配字段:

分组情况下,group(),start(),end(),span()都可以通过传入索引来得到各自组对应的值,也就是每个组对应的其实位置结束位置,都是相互独立的——也就意味着对于子表达式的嵌套来说,匹配的原理一致。比如:

我们通常使用分组的方法对字符串进行特定格式的取值,一般情况下,对于元素比较多,顺序不确定的集合,更适合的方式是字典而不是列表,那么group能不能通过传入键值而不是索引进行取值呢?这个当然是可以的。正则的分组中提供了组名的机制,不只是最终取值方便,对于正则表达式内部的引用作用更大。还是刚才的存货的例子,重新写一下:

索引方式:

示例中,用?P<ID>.*代替了.*,这样分组后的匹配就可以支持关键字的方式进行取值。事实上,正则中的这种方法本质是给组命名,对于复杂的正则可能需要不断重复之前已经匹配到的东西,组名的方式就很清晰和方便了。另外,?P的写法是python中的扩展,大写的P代表python,一般其他的正则中写法不同,标准的正则中没有这个字母。

这种扩展源于perl的正则表达式的扩展,事实上从perl5.0以后对正则的支持,re模块大部分都支持。正则的扩展一般来说同样是使用元字符来标识,perf中使用?来标识,因为?即非转义,又可以直接用在(后进行标识。Python中采取同样的方法,在?后加上大写的P进行标识,省去转义的麻烦。

无捕获组

和分组以及组名比起来,无捕获组很容易。它的匹配方式和效率和分组没有任何区别,甚至也可以重复子表达式,通常当我们对匹配组的内容不感兴趣的时候,需要用到无捕获组。既然不去捕获,那么它的意义何在?一般来说,无捕获组的意义不在于它自己本身,而在于对其他分组的影响——类似于一个占位的作用。当表达式改变或者分组改变,可以很简单的修改表达式进行分组的匹配,python中用?:标识。看一个简单的无捕获组的示例:

向后引用

前面几个例子虽然都是使用分组来对字符串进行取值,但是之前提到了分组的根本原因是为了处理字符串的重复。向后引用用于重复匹配和搜索到前面已经匹配到的分组内容,同样的,索引和组名的方式都支持,但是最好还是使用组名的方式,虽然写起来稍微多一些,但是很清楚,不容易出问题,尤其是在正则这种看起来比较复杂的逻辑中。下面是一个经典的示例,匹配两个重复的单词:

分别用索引和组名完成了上面的匹配,注意组名向后引用的格式:(?P=name)

零宽断言

零宽断言,从字面上理解,就是一种断言。正则中的断言同样是一种标识,其实之前的^$\b这些标识位置的也都是一种断言。零宽断言的目的是为了匹配字符串的位置,而不是字符串和文本本身,基本上正则中的断言都是匹配位置的。通俗的讲,就是这种断言同样是为了寻找某个位置,这个位置满足一定的条件,这就是零宽断言。零宽断言按照匹配方向和是否肯定分为四种情况:

向前界定:

顺序肯定匹配(?=exp),表示被匹配的文本右边要匹配exp表达式,示例如下:

向前否定界定:

顺序否定匹配(?!),表示后面不匹配的exp,示例如下:

向后界定:

逆序肯定匹配(?<=exp),表示左面匹配exp表达式,注意所有反向界定的匹配文本必须定长!,示例如下:

向后否定界定:

逆序否定匹配(?<),表示左边不匹配exp,示例如下:

平衡组和递归

正则表达式中,平衡组和递归属于稍微复杂一点的东西,不过好像Python并不提供支持,我了解到的.net framework是提供这种正则的支持,其他语言有些不支持,有些语法不同,python中暂时还没有找到。他们在匹配html这样复杂的文本时用到的比较多,一般来说也都可以通过和组的组合来解决。这个属于稍微高级一点的东西,这里暂时不讨论。

时间: 2024-10-09 22:30:39

Python基础——windows自动化篇(九)-正则表达式的相关文章

【Python基础】入门篇

Python(发音:/?pa?θɑ?n/),是一种面向对象.直译式的计算机程序语言,具有近二十年的发展历史.它包含了一组功能完备的标准库,能够轻松完成很多常见的任务.它的语法简单,与其它大多数程序设计语言使用大括号不一样,它使用缩进来定义语句块.由Guido van Rossum于1989年底发明,第一个公开发行版发行于1991年.官方站点:https://www.python.org/ Python能做什么? Python是一门综合性的语言,几乎能用python做任何事情,下面列举几个最广泛的

python基础-第六篇-6.2模块

python之强大,就是因为它其提供的模块全面,模块的知识点不仅多,而且零散---一个字!错综复杂 没办法,二八原则抓重点咯!只要抓住那些以后常用开发的方法就可以了,哪些是常用的?往下看--找答案~ 模块定义 模块,用一砣代码实现了某个功能的代码集合. 类似于函数式编程和面向过程编程,函数式编程则完成一个功能,其他代码用来调用即可,提供了代码的重用性和代码间的耦合.而对于一个复杂的功能来,可能需要多个函数才能完成 (函数又可以在不同的.py文件中),n个 .py 文件组成的代码集合就称为模块.

python基础1--小结篇

如果有别的编程语言基础,python属于极好上手的一门语言.应用上,用“自取所需”来描述,最为贴切. 首先,放上一些推荐. 安装上: 1.python3.5.1(推荐官网直接下载,自带IDLE),安装不麻烦,记得增加环境变量即可 2.编辑器:sublime 其实,并没有使用很多,但是推荐的人超多 ,破解版网上很多,按资源下载即可 3.IDE: 强推 pycharm 对JetBrains软件执着的热爱  方便又美观 网上能找到找到注册码,学生用edu邮箱可以免费使用,当然,支持正版! 熟悉上: 语

Python基础学习 总结篇

Python基础学习总结 先附上所有的章节: Python学习(一)安装.环境配置及IDE推荐 Python学习(二)Python 简介 Python学习(三)流程控制 Python学习(四)数据结构(概要) Python学习(四)数据结构 —— int float Python学习(四)数据结构 —— str Python学习(四)数据结构 —— bool Python学习(四)数据结构 —— list tuple range Python学习(四)数据结构 —— set frozenset

Python基础学习笔记(九)常用数据类型转换函数

参考资料: 1. <Python基础教程> 2. http://www.runoob.com/python/python-variable-types.html 3. http://www.liaoxuefeng.com/wiki/001374738125095c955c1e6d8bb493182103fac9270762a000 常用数据类型转换函数: 函数 描述 int(x [,base]) 将x转换为一个整数 long(x [,base] ) 将x转换为一个长整数 float(x) 将x

python基础-第五篇-5.4正则表达式

正则基础知识 正则表达式是通过调用re模块实现的 在python里,正则表达式处理对象为字符串,所以正则里方法和字符串的方法有很多相似的地方:re.findall和find,re.split和split,re.sub和replace 普通字符和元字符 普通字符 大多数的字符和字母都为普通字符 元字符 在正则里,有其特殊的功能的字符称为元字符,如:. ^ $ * + ? {} | () \ .    除了换行符任意一个字符进行匹配 import re strs = 'ji154\n651jia*-

Python基础第四篇—模块

一.模块 模块,是用一堆代码实现了某个功能的代码集合,模块分为三种:自定义模块(自己定义).内置模块(python自带).开源模块 导入模块 (1).导入一个py文件,解释器解释该py文件 (2).导入一个包,解释器解释该包下的 __init__.py 文件 #模块导入 import module from module.xx import xx from module.xx.xx import * from module.xx.xx import xx as rename #自己给模块定义一个

Python 基础【第一篇】环境部署

一.Windows基础环境配置部署 1.1.下载python安装程序 下载地址:https://www.python.org/ftp/python/3.4.1/python-3.4.1.msi 1.2.运行 python-3.4.1.msi 1.3.这里可以选择安装路径(默认即可) 1.4.一路默认下一步 直到安装完毕 1.5.设置环境变量 1.5.1.我的电脑---->右键“属性”---->高级系统设置 1.5.2.环境变量 1.5.3找到系统变量中的“Path” 值 如果没有就添加,名称为

python基础2--小结篇

继续python相关基础的梳理: 1.正则表达式 这里放上一张很实用的表格和一个常见的例子: 例子:电子邮箱验证的正则表达式 1 import re 2 re_email=re.compile(r'^([\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+)$') 3 re_email.match('[email protected]').groups() 4 re_email.match([email protected]').groups() 2.接下来又谈数据 既然pyth