上一章节我们先将了re模块中最为重要的几个函数 search、match、findall 、split 、sub 和分组的概念,同时我们也提到了,在正则表达式中重要的概念就是替换的内容和替换的次数,那么今天我们就来介绍着两部分的内容,一开始我们先介绍替换(匹配)的内容,也即是pattern中的内容。
现在先假设一种情况,我们想查找一堆字符串“海水井水泉水都是水,但是只有海水不是直接可以引用的水”中和关于对水类型的有关的描述,例如海水、泉水、井水,根据上一章节的内容,我们需要知道需要使用findall函数,ok直接上代码。
>>> import re>>> asume = '海水井水泉水都是水,但是只有海水不是直接可以引用的水'>>> re.findall('海水',asume)['海水', '海水']>>> re.findall('井水',asume)['井水']>>> re.findall('泉水',asume)['泉水']
根据上面的代码,我们找到了自己想要找的内容,但是有没有发现,这样很麻烦,作为人类发明的最有智慧的机器,电脑怎么可能让您如此麻烦的浪费人生美好的时间,这里我们先介绍英文字符点号.,不要小看这个小小的点号,在re中,它可以表示一位任何内容(当然除了\n,分行符除外),请注意一个点只能表示一位一个内容,毕竟做人不能太贪心嘛,那么上面的代码就可以改写为
>>> re.findall('.水',asume)['海水', '井水', '泉水', '是水', '海水', '的水']
我们修改了findall函数中pattern的内容,水字前面改为一点 . ,这次是不是把我们想要找的水的类型都找到了,但是又出现了一个小问题,把一些莫名其妙的水也找了出来,比如 是水 的水。哎,人生啊,大起大落的,不要灰心,我们还有办法,这里介绍另一个东东 |,英文输入法的竖杆,它在re中表示或的意思,于是我们又要修改上面代码:
>>> re.findall('(泉|井|海)水',asume)['海', '井', '泉', '海']
这里我们查找水字前面内容为泉或者井或者为海的字,也行有人想说,我想找的是两个字啊,怎么才有一个字呢,很简单,结合我前面的降到的 list 解析式自己手动添加一个水字就行,当然如果你够大胆,肯定想反正那个pattern中的水字结果中不会保留,我们干嘛不用上面讲到的点来的替代,当然这样操作是没有问题的。还是上代码:
>>> re.findall('(泉|井|海).',asume)['海', '井', '泉', '海']
如果您真的想在结果查询中就保留水,我们先试试下面的代码
>>> re.findall('泉|井|海水',asume)['海水', '井', '泉', '海水']
忧伤啊,只有海水是两个字,其他还是一个字,这个就涉及到|起作用的范围了,| 会把前后的内容视为一个整体,所以刚刚要查询的就是泉 或者井或者海水,如果想用竖杆,同时保留水字,欢迎自己尝试。
刚刚我们讲到了两个内容.和|,那么re中到底有哪些特殊字符可以表示内容呢欢迎看下表,表中详细介绍了常用的re特殊字符串和表示的内容。
表示法 | 表述 | 式例 |
character | 匹配文本字符串的字面值 | abc |
re1 I re2 | 匹配正则表达式re1或re2 | abcl bar |
. | 匹配任何字符串(除了\n之外) | a.c |
^ | 匹配字符串起始部分 | ^Dear |
$ | 匹配字符串终止部分 | abcd.h$ |
\d和\D | 匹配任何十进制数字,和[0-9]相同(\D与\d相反,不匹配任何非数值型的数字) | data\d.txt |
\w和\W | 匹配任何字母数字字符,与[A-Za-z0-9_]相同(\W与之相反) | [A-Za-z_]\w+ |
\s | 匹配任何空格字符,与[\n\t\r\n\f]相同(与\S相反) | of\sthe |
>>> asume = '1234556dddd'>>> re.findall('\d',asume)['1', '2', '3', '4', '5', '5', '6']# \d指代0到9 任何一个数字,1到6都被找出来了>>> re.findall('\D',asume)# 任何非数字字符都被找出来了['d', 'd', 'd', 'd']>>> re.findall('\w','123aaa@#')['1', '2', '3', 'a', 'a', 'a']#任何数字和a到Z都被找出来了
^和$这两个目前用不到,这里先不介绍,有兴趣的小伙伴可以先自己了解,今后如果我们需要用到,会进一步介绍。
上面我们介绍了re中的特殊字符和指代的内容,下面我们开始介绍如果控制替代的次数。还是先假设一种场景,我们想从一堆字符串中"我是中国人民解放军第73集团军一名中国军人,我们的队伍都是从中国红军演变而来的"中找到以中开头,军结尾的内容,那么我们分析发现有中国人民解放军、中国军、中国红军这3个内容,那么怎么用代码表示呢,这里我们引入查找次数控制系统,先上代码
>>> asume = "我是中国人民解放军第73集团军一名中国军人,我们的队伍都是从中国红军演变而来的">>> re.findall('中.*军',asume)['中国人民解放军第73集团军一名中国军人,我们的队伍都是从中国红军']
这里我们使用了一个特殊字符星号*,这个符号可以控制其前面一个位置中的内容出行0次或者n次,分析我们的结果:'中国人民解放军第73集团军一名中国军人,我们的队伍都是从中国红军',确实是以中为开头,军结尾,中的点为任何内容,然后这个内容可能出行N或者0次,所以 从国开始到红结束,这个内容就是.*匹配的结果,可是虽然这个结果满足re中的规则,但是不满足我们需求的结果,那么我们再引入一个控制符?,对就是问好,默认的re中,在查找匹配内容采用的贪婪模式,所谓贪婪默认就是在满足规则的情况下,查找尽可能多的内容,如果使用了?,这个时候re在匹配的时候就采用非贪婪模式,也就是只要是满足规则的内容就好,我们修改一下上面的代码:
>>> re.findall('中.*?军',asume)['中国人民解放军', '中国军', '中国红军']
运行修改过的代码,是不是满足了我们的需求,这里强调一下?,这个特殊字符一般位于次数控制器后面。
除了星号还有加号和大括号来控制次数,下表有详细的介绍,还是想查找上面的内容,使用大括号控制器
>>> re.findall('中.{1,5}军',asume)['中国人民解放军', '中国军', '中国红军']
我们使用了{1,5}来作为次数控制器,这里的意思就是.点号代表的内容可以出现1到5次,所以满足我们的查询要求,我们将大括号里面的内容修改为1,4,即星号所指代的内容最多出现4次,所以 国人民解放 这个段内容有5个字,就不满足规则要求,没有被查到。
>>> re.findall('中.{1,4}军',asume)['中国军', '中国红军']
表示法 | 表述 | 式例 |
* | 匹配0次或多次前面出现的正则表达式 | [A-Za-z0-9]* |
+ | 匹配1次或多次前面出现的正则表达式 | [a-z]+.com |
? | 匹配0次或1次前面出现的正则表达式 | goo? |
{N} | 匹配N次前面出现的正则表达式 | [0-9]{3} |
{M,N} | 匹配M~N次前面出现的正则表达式 | [0-9]{5,9} |
[...] | 匹配来自字符集的任意单一字符 | [aeiou] |
[..x-y..] | 匹配x~y范围中的任意单一字符 | [0-9],[A-Za-z] |
[^...] | 不匹配此字符集中出现的任何一个字符,包括某一范围的字符 | [aeiou],[A-Za-z] |
*? | 用于匹配上面频繁出现符号的非贪婪版本(*、+、?、{}) | .*?[a-z] |
OK,本小节讲解先到这里,本期的作业,重写3遍上面的提到语句。还是那句话,欢迎截图,截图越多的同学,今后的作业被选中,点评的概率越大。
本系列由解忧数据出品
专注城市和地理数据
三w点jieyoudata点com(www.jieyoudata.com)
找数据,来解忧——它难道不香吗
-一点分享 更多选择-
欢迎加入解忧数据
Jieyou data
http://www.jieyoudata.com
解忧公众号
微信号 : 解忧数据
欢迎您