Python 语言及其应用 Chapter_7_Note 1 正则表达匹配

来源:互联网 发布:日韩男士帽子 知乎 编辑:程序博客网 时间:2024/06/07 00:45

这个章节以前没细看,现在接着看吧。

与之相关的功能都位于标准库模块re 中,因此首先需要引用它。你需要定义一个用于匹配的模式
pattern)字符串以及一个匹配的对象:源(source)字符串

re.match函数

re.match(pattern,string, flags=0)

pattern匹配的正则表达式string要匹配的字符串。flags标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。

re.match 尝试从字符串的起始位置匹配一个模式,如果不是起始位置匹配成功的话,match()就返回none

result = re.match('You', 'Young Frankenstein')
这里,'You' 是模式,'Young Frankenstein' 是——你想要检查的字符串。match() 函数用于查看源是否以模式开头


使用match()进行准确匹配
字符串'Young Frankenstein' 是以单词'You' 开头的吗?以下是一些带注释的代码:
>>> import re
>>> source = 'Young Frankenstein'
>>> m = re.match('You', source) # 从源字符串的开头开始匹配
>>> if m: # 匹配成功返回了对象,将它输出看看匹配得到的是什么
... print(m.group())
...
You
>>> m = re.match('^You', source) # 起始锚点也能起到同样作用
>>> if m:
... print(m.group())
...
You
尝试匹配'Frank' 又会如何?
>>> m = re.match('Frank', source)
>>> if m:
... print(m.group())
...
这一次,match() 什么也没有返回,if 也没有执行内部的print 语句。如前所述,match()
只能检测以模式串作为开头的源字符串。但是search() 可以检测任何位置的匹配:
>>> m = re.search('Frank', source)
>>> if m:
... print(m.group())
...
Frank

改变一下匹配的模式:
>>> m = re.match('.*Frank', source)
>>> if m: # match返回对象
... print(m.group())
...
Young Frank
以下是对新模式能够匹配成功的简单解释:
• . 代表任何单一字符;
• * 代表任意一个它之前的字符,.* 代表任意多个字符(包括0 个);

• Frank 是我们想要在源字符串中某处进行匹配的短语。

match() 返回了匹配.*Frank 的字符串:'Young Frank'。


上面这个案子,如果后面不加span()这个参数,就无法返回(0,3)这个元组,这个元组代表着匹配到的索引位置是从0开始,3(但不包含3)结束.

实际上span()的意思就是  m.span() 返回一个tuple表示(m.start(), m.end()) 

然后,如果不是从开头位置开始匹配成功的,或者是匹配的str根本没有在需要匹配的字符串中的,那么,返回None.

就如上面例子中组后2次测试。

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

使用search()寻找首次匹配
你可以使用search() 在源字符串'Young Frankenstein' 的任意位置寻找模式'Frank',无
需通配符.*:
>>> m = re.search('Frank', source)
>>> if m: # search返回对象
... print(m.group())
...
Frank

笔记部分:search和match功能有点类似,但是区别在于,match只能从头开始匹配,search可以从任意位置开始匹配,但是,search只能匹配一次

我做了一个实验,如下

前面的pattern里面是匹配0-9的数字,后面的resource里面明明有2和4两个数字,但是由于是search功能,所以只能匹配到一个。所以返回2.


这里补一个基础知识,也就是上面例子里面的[0-9],这里的[]不是代表list的意思,而是字符集,解释如下

字符集

字符集是在中括号( [] )中包含字符串。字符集可以匹配它所包含的任意字符。即'[pj]ython'可以匹配pythonjython

可以使用范围,如 '[a-z]' 可以匹配 a 到 z 的任意一个字符。'a-zA-Z0-9' 可以匹配任意大小写的一个字母或数字。

反转字符集

我们也可以对字符集进行反转,比如 '[^abc]' 匹配除了a、b和c之外的任何字符。

字符集中的特殊字符

特殊字符在模式中做文本字符,而不是正则表达式运算符的话需要对其进行转义。但是在字符集中并不需要,只有以三种情况下,需要将特殊字符作为普通文本使用时,需要对字符进行转义:

^ 脱字符作为字符集的开头

] 右中括号作为字符集的开头

- 横线(字符范围)作为字符集的开头


---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

使用findall()寻找所有匹配
之前的例子都是查找到一个匹配即停止。但如果想要知道一个字符串中出现了多少次字母
'n' 应该怎么办?
>>> m = re.findall('n', source)
>>> m # findall返回了一个列表
['n', 'n', 'n', 'n']
>>> print('Found', len(m), 'matches')
Found 4 matches
将模式改成'n',紧跟着任意一个字符,结果又如何?
>>> m = re.findall('n.', source)
>>> m
['ng', 'nk', 'ns']
注意,上面例子中最后一个'n' 并没有匹配成功,需要通过? 说明'n' 后面的字符是可选的
>>> m = re.findall('n.?', source)
>>> m
['ng', 'nk', 'ns', 'n']


这里加一个基础知识补习:关于正则表达式里面的问号?

 问号代表:匹配表达式0次或者1次,相当于 {0,1},比如:"a[cd]?"可以匹配 "a","ac","ad"

也就是说,问号可以匹配前面的单个字符,0次,或者1次!就如上面的例子里面,匹配0次,就匹配成a,匹配1次并选择字符集内的c,就是ac,剩下的就是ad。

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

使用split()按匹配切分
下面的示例展示了如何依据模式而不是简单的字符串(就像普通的split() 方法做的)将
一个字符串切分成由一系列子串组成的列表:
>>> m = re.split('n', source)
>>> m # split返回的列表
['You', 'g Fra', 'ke', 'stei', '']

这里注意,最后一个n被匹配掉以后,最后一个元素是"",而不是没有

使用sub()替换匹配
这和字符串replace() 方法有些类似,只不过使用的是模式而不是文本串:
>>> m = re.sub('n', '?', source)
>>> m # sub返回的字符串
'You?g Fra?ke?stei?'


---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
已经见过的一些基本模式:
• 普通的文本值代表自身,用于匹配非特殊字符;
• 使用. 代表任意除\n 外的字符;
• 使用* 表示任意多个字符(包括0 个);
• 使用? 表示可选字符(0 个或1 个)。
接下来要介绍一些特殊字符,参见表7-3。
表7-3:特殊字符
模式匹配
\d 一个数字字符
\D 一个非数字字符
\w 一个字母或数字字符
\W 一个非字母非数字字符
\s 空白符
\S 非空白符
\b 单词边界(一个\w 与\W 之间的范围,顺序可逆)
\B 非单词边界

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

模式标识符
模式匹配
abc 文本值abc
(expr) expr
expr1 | expr2 expr1 或 expr2
. 除\n 外的任何字符
^ 源字符串的开头
$ 源字符串的结尾
prev? 0 个或1 个prev
prev* 0 个或多个prev,尽可能多地匹配
prev*? 0 个或多个prev,尽可能少地匹配
prev+ 1 个或多个prev,尽可能多地匹配
prev+? 1 个或多个prev,尽可能少地匹配
prev{m} m 个连续的prev
prev{m, n} m 到n 个连续的prev,尽可能多地匹配
prev{m, n}? m 到n 个连续的prev,尽可能少地匹配
[abc] a 或b 或c(和a|b|c 一样)
[^abc] 非(a 或b 或c)
prev (?=next) 如果后面为next,返回prev
prev (?!next) 如果后面非next,返回prev
(?<=prev) next 如果前面为prev,返回next
(?<!prev) next 如果前面非prev,返回next

下面来看例子:
>>> source = '''I wish I may, I wish I might
... Have a dish of fish tonight.'''
首先,在源字符串中检索wish
>>> re.findall('wish', source)
['wish', 'wish']
接着,对源字符串任意位置查询wish 或者fish:        #这里就是要用到  |  符号
>>> re.findall('wish|fish', source)
['wish', 'wish', 'fish']
从字符串开头开始匹配wish
>>> re.findall('^wish', source)
[]

从字符串开头开始匹配I wish:               #注意,这里即使是用了findall,但是由于有了^符号,等于是执行了从开头匹配,所以只匹配到一个I wish
>>> re.findall('^I wish', source)
['I wish']
从字符串结尾开始匹配fish
>>> re.findall('fish$', source)
[]
最后,从字符串结尾开始匹配fish tonight.:
>>> re.findall('fish tonight.$', source)
['fish tonight.']

^ 和$ 叫作锚点(anchor):^ 将搜索域定位到源字符串的开头,$ 则定位到末尾。上面例
子中的.$ 可以匹配末尾的任意字符,包括句号,因此能成功匹配。但更准确地说,上面
的例子应该使用转义符将. 转义为句号
,这才是我们真正想示意的纯文本值匹配:
>>> re.findall('fish tonight\.$', source)
['fish tonight.']


接下来查询以w 或f 开头,后面紧接着ish 的匹配
>>> re.findall('[wf]ish', source)
['wish', 'wish', 'fish']

查询以若干个w、s 或h 组合的匹配:        #这里有个重点需要记住,看书的时候不理解为什么不匹配到单个的s,后来看了关于 + 和 +?的区别,知道了,就是+号是表示尽可能
>>> re.findall('[wsh]+', source)                  #多地匹配,什么意思呢?就是当发现按照wsh组合来匹配资源内的字符,能匹配sh的时候,他就不单独匹配s和h
['w', 'sh', 'w', 'sh', 'h', 'sh', 'sh', 'h']                #反之,当使用+?的时候,他就尽可能少地匹配,既是匹配发现了sh,也是单独匹配成s和h,做了实验,如下可以看


从这里就可以看到+和+?的区别




查询以ght 开头,后面紧跟一个非数字非字母字符的匹配:
>>> re.findall('ght\W', source)
['ght\n', 'ght.']

查询以I 开头,后面跟着wish 的匹配(wish 出现次数尽量少):
>>> re.findall('I (?=wish)', source)
['I ', 'I ']

最后查询以wish 结尾,前面为I 的匹配(I 出现的次数尽量少):
>>> re.findall('(?<=I) wish', source)
[' wish', ' wish']

有时,正则表达式的语法可能会与Python 本身的语法冲突。例如,我们期望下面例子中的
模式能匹配任何以fish 开头的词:
>>> re.findall('\bfish', source)
[]
为什么没有匹配成功?第2 章曾提到,Python 字符串会使用一些特殊的转义符。例如上面
的\b,它在字符串中代表退格,但在正则表达式中,它代表一个单词的开头位置。因此,
把Python 的普通字符串用作正则表达式的模式串时需要特别注意,不要像上面一样与转义
符产生冲突。或者在任何使用正则表达式的地方都记着在模式串的前面添加字符r,这样
可以告诉Python 这是一个正则表达式,从而禁用字符串转义符
,如下所示:
>>> re.findall(r'\bfish', source)
['fish']

这里补一个基础知识:\b和\B
\b表示要匹配的字符属于一个单词的边界,可以是左边界或者右边界,取决于你把\b放置的位子,看下面的例子
而\B和\b的意思正好相反,匹配非边界字符。


---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

模式:定义匹配的输出
当使用match() 或search() 时,所有的匹配会以m.group() 的形式返回到对象m 中。如果
你用括号将某一模式包裹起来,括号中模式匹配得到的结果归入自己的group(无名称)
中,而调用m.groups() 可以得到包含这些匹配的元组,如下所示:
>>> m = re.search(r'(. dish\b).*(\bfish)', source)
>>> m.group()                               #group返回的是整个匹配的模式内容
'a dish of fish'
>>> m.groups()                             #groups返回的是括号内的匹配出来的内容!!
('a dish', 'fish')

所以我做了以下实验,当用group的时候,他会将两个括号中间的.*一起返回出来,也就是 ' of '
但是你如果对group设置参数,他也是只对应括号内的内容。
而groups对应的只是括号内的内容,并返回元组。



0 0
原创粉丝点击