《python3网络爬虫开发实战 第二版》之基本库的使用-正则表达式 详解

本文介绍了正则表达式的基础知识,包括match方法用于从字符串起始位置匹配,group方法用于提取匹配内容,以及.*的贪婪和非贪婪匹配。还讨论了修饰符如re.S的作用,以及search、findall和sub方法在字符串查找和替换中的应用。最后提到了compile方法用于编译正则表达式以提高效率。
摘要由CSDN通过智能技术生成

正则表达式

正则表达式介绍

正则表达式是用来处理字符串的强大工具,有自己特定的语法结构。
可以使用正则表达式进行字符串的检索,替换,匹配验证
对于爬虫来说,使用正则表达式可以简化从HTML提取信息的步骤
匹配URL的正则表达式[a-zA-Z]+://[^\s]*

match

match 方法会尝试从字符串的起始位置开始匹配正则表达式,如果匹配,就返回匹配成功的结果;如果不匹配,就返回None。
实例如下:

def match_test():
    import re
    content = 'Hello 123 45678 World_This is a Regex Demo'
    result = re.match('^Hello\s\d\d\d\s\d{5}\s\w{10}', content)
    print(result)  # 返回匹配的结果
    print(result.group())  # 返回匹配到的内容
    print(result.span())   # 匹配的范围, 匹配到的结果字符串在原字符串中的位置范围

实例执行的结果如下图所示

在这里插入图片描述

'^Hello\s\d\d\d\s\d{5}\s\w{10}'
^ 表示匹配字符串的开头
\d 表示数字 \d\d\d 表示连续三个数字
\d{5} 表示连续5个数字,这种方式更简单一些
\s 表示一个空格
\w{10} 表示匹配10个字母以及下划线。

匹配目标 group

使用match方法可以实现匹配,
如果从一段文本中提取出E-mail 地址或电话号码,
可以使用括号()将想要提取的字符串括起来。
() 实际上标记了一个子表达式的开始和结束文职,被标记的每个子表达式一次对应每个分组,调用group方法传入分组的索引即可获取提取结果。
实例如下:
实例中的\d+ 表示至少一个数字,至多不封顶

def match_test1():
    import re
    content = 'Hello 1234567 World_Test 45897546 is a regex demo'
    result = re.match('^Hello\s(\d+)\sWorld_Test\s(\d+)', content)
    print(result)
    print('不带序号',result.group(), sep='\t')
    print('序号为0',result.group(0),sep='\t')
    print('序号为1', result.group(1),sep='\t')
    print('序号为2', result.group(2),sep='\t')

实例运行的结果如下图所示
从运行的结果可以看出,不带序号与序号为0时输出的结果是一致的,都是匹配到的完整的字符串
想要提取的子字符串,其索引应当从1开始,而不是0

在这里插入图片描述

通用匹配 .*

前文的空白字符使用\s,数字使用\d,这样写比较复杂
有一个万能匹配就是.* .可以匹配除了换行符之外的任意字符 * 表示前一个字符可以无限次
我们使用.* 来进行匹配,实例代码如下

def match_test2():
    import re
    content = 'Hello 1234567 World_Test 45897546 is a regex demo'
    result = re.match('^Hello.*is', content)
    print(result)
    print(result.group())  # 返回匹配到的内容
    print(result.span())   # 匹配的范围, 匹配到的结果字符串在原字符串中的位置范围

匹配的结果如下图所示
在这里插入图片描述

贪婪匹配与非贪婪匹配

.*会匹配尽可能多的字符--------> 贪婪匹配
.*?会匹配尽可能少的字符-------> 非贪婪匹配

通过一个实例来对比贪婪匹配与非贪婪匹配的不同
实例目标:匹配目标字符串中的所有的数字

def match_test3():
    import re
    content = 'Hello 1234567 World_Test is a regex demo'
    result1 = re.match('^Hello.*(\d+)', content)   # 使用.* 来匹配 Hello后面的空格
    result2 = re.match('^Hello.*?(\d+)', content)  # 使用.*?来匹配 Hello后面的空格
    result3 = re.match('^Hello.*?(\d+).*?', content)  # 使用.*?匹配后面的字符串
    result4 = re.match('^Hello.*?(\d+).*', content)   # 使用.* 匹配后面的字符串
    print('.*匹配空格:', result1.group(1))
    print('.*?匹配空格:', result2.group(1))
    print('.*?匹配尾字符串:', result3)
    print('.*匹配尾字符串:', result4)

代码执行的结果如下图所示:

在这里插入图片描述

从代码运行的结果可以看出:
.* 尽可能匹配更多的字符串,由于\d+ 至少有一个数字,就留下了一个数字7留给\d+进行匹配
.*?尽可能匹配更少的字符串, 由于\d+可以把所有的数字都匹配上,因此.*? 就匹配上了一个空格
在进行字符串末尾匹配的时候,由于.*? 尽可能少地匹配,因此就一个不匹配,就出现第三种结果
在进行字符串末尾匹配的时候,由于.* 尽可能多地匹配,因此所有的字符都匹配上了,就出现了第四种结果

修饰符

如果一个字符串中存在换行符,那么在使用.*或者.*?就匹配不上了
修饰符re.S 可以使.*匹配包括换行符在内的所有字符。
实例代码如下:

def match_test4():
    import re
    content = '''Hello 1234567 World_Test 
    is a regex demo
    '''
    result = re.match('^Hello.*?(\d+).*', content, re.S)
    print(result.group())

代码执行的结果如图所示
在这里插入图片描述

常见的修饰符

修饰符描述
re.I使匹配对大小写不敏感
re.M多行匹配,影响^以及$
re.S匹配包括换行符在内的所有字符
re.U根据Unicode字符集解析字符。会影响\w, \W, \b, \B

转义匹配

在使用.*进行字符匹配的时候,如果目标字符串中本身就含有.怎么办?
只需要在用作正则匹配模式的特殊字符时,在此字符之前加\转义一下即可。
以匹配网址为例,实例如下:

def match_test5():
    import re
    content = '(百度) www.baidu.com'
    result = re.match('\(百度\) www\.baidu\.com', content)
    print(result)

代码执行的结果如下图所示
在这里插入图片描述

search

match方法是从自字符串的开头开始匹配的,如果开头不匹配,整个匹配就失败了。
因此match方法在使用时,需要考虑目标字符串开头的内容
更适合检测某个字符串是否符合某个正则表达式的规则

search方法在匹配时会扫描整个字符串,然后返回第一个匹配成功的结果。
在匹配时,search方法会依次以每个字符作为开头扫描字符串,直到找到第一个符合规则的字符串,然后返回匹配内容
如果扫描完还没有找到符合规则的字符串,就返回None
search方法的用法与match方法类似。
需要注意的是,在对HTML文本进行匹配时,由于HTML文本包含换行符,因此需要加上re.S修饰符,以免出现匹配不到的问题

findall

search 方法获取得到的是与正则表达式相匹配的第一个字符串
如果想要获取与正则表达式相匹配的所有字符串,就需要用到findall方法。

sub

前面提到的match,search,findall三个方法都是通过正则表达式进行查找
使用sub可以通过正则表达式对字符串进行修改
例如将一个字符串中的数字换成空格,实例代码如下:

def sub_test():
    import re
    content = 'hijs2jjhj34bjhg6kj3kj7hg'
    result = re.sub('\d+', ' ', content)
    print(result)

代码执行的结果如下图所示
在这里插入图片描述

compile

这个方法可以将正则字符串变异成正则你倒是对象,以便在后面的匹配中复用
实例代码如下:

def compile_test():
    import re
    content1 = '2019-02-21 12:12'
    content2 = '2019-02-24 12:17'
    content3 = '2019-02-25 12:18'
    content4 = '2019-02-26 12:19'
    pattern = re.compile('\d{2}:\d{2}')
    result1 = re.sub(pattern, '', content1)
    result2 = re.sub(pattern, '', content2)
    result3 = re.sub(pattern, '', content3)
    result4 = re.sub(pattern, '', content4)
    print(result1, result2, result3, result4)

代码运行的结果如图所示

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值