正则表达式是用来处理字符串的强大工具,有自己特定的语法结构。
可以使用正则表达式进行字符串的检索,替换,匹配验证
对于爬虫来说,使用正则表达式可以简化从HTML提取信息的步骤
匹配URL的正则表达式[a-zA-Z]+://[^\s]*
match 方法会尝试从字符串的起始位置开始匹配正则表达式,如果匹配,就返回匹配成功的结果;如果不匹配,就返回None。
实例如下:
def match_test():import recontent = '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个字母以及下划线。
使用match方法可以实现匹配,
如果从一段文本中提取出E-mail 地址或电话号码,
可以使用括号()将想要提取的字符串括起来。
() 实际上标记了一个子表达式的开始和结束文职,被标记的每个子表达式一次对应每个分组,调用group方法传入分组的索引即可获取提取结果。
实例如下:
实例中的\d+
表示至少一个数字,至多不封顶
def match_test1():import recontent = '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 recontent = '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 recontent = '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 recontent = '''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 recontent = '(百度) www.baidu.com'result = re.match('\(百度\) www\.baidu\.com', content)print(result)
代码执行的结果如下图所示
match方法是从自字符串的开头开始匹配的,如果开头不匹配,整个匹配就失败了。
因此match方法在使用时,需要考虑目标字符串开头的内容
更适合检测某个字符串是否符合某个正则表达式的规则
search方法在匹配时会扫描整个字符串,然后返回第一个匹配成功的结果。
在匹配时,search方法会依次以每个字符作为开头扫描字符串,直到找到第一个符合规则的字符串,然后返回匹配内容
如果扫描完还没有找到符合规则的字符串,就返回None
search方法的用法与match方法类似。
需要注意的是,在对HTML文本进行匹配时,由于HTML文本包含换行符,因此需要加上re.S修饰符,以免出现匹配不到的问题
search 方法获取得到的是与正则表达式相匹配的第一个字符串
如果想要获取与正则表达式相匹配的所有字符串,就需要用到findall方法。
前面提到的match,search,findall三个方法都是通过正则表达式进行查找
使用sub可以通过正则表达式对字符串进行修改
例如将一个字符串中的数字换成空格,实例代码如下:
def sub_test():import recontent = 'hijs2jjhj34bjhg6kj3kj7hg'result = re.sub('\d+', ' ', content)print(result)
代码执行的结果如下图所示
这个方法可以将正则字符串变异成正则你倒是对象,以便在后面的匹配中复用
实例代码如下:
def compile_test():import recontent1 = '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)
代码运行的结果如图所示