正则表达式详解

本文介绍了如何使用Python的re模块进行正则表达式操作,包括基本的字符串查找、使用字符集、数量词、贪婪/非贪婪匹配、边界匹配符、分组以及re.findall、re.sub和match/search函数的应用。
摘要由CSDN通过智能技术生成

正则表达式

为避免提示正则表达式和转义字符冲突,如\d,用\\d来表示正则表达式,把\本身给转义掉

判断字符串里面是否包含某个字符串

a = 'C|C++|Java|Python|PHP|JavaScript|C#|Ruby|Swift'

方法一:

print(a.index('C++'))

方法二:

print('C++' in a)

方法三:正则表达式
使用正则表达式要通过re模块
re.findall函数:字符串查找

import re
a = 'C|C++|Java|Python|PHP|JavaScript|C#|Ruby|Swift'
r = re.findall('Python', a)
print(r)
#输出:['Python'] ----- 是一个列表

问题:用正则表达式提取出下面字符串中所有数字

import re
a = 'C1C++4Java7Python0PHP4JavaScript3C#8Ruby9Swift'
r = re.findall('\d+', a)  
#正则表达式中 '\d'表示数字
print(r)
#输出:['1', '4', '7', '0', '4', '3', '8', '9']

字符集

  • 只能输出一个字符

\d表示数字, [0-9]
\D表示字母, [A-Za-z]
\w表示数字和字母(无论大小写)以及下划线_(不包括其他符号) [A-Za-z0-9_]
\W表示符号(空格&\n,等其他符号)(不包括下划线)
\s表示空白字符(空格,制表符,换行符) [\t\n\r\f\v]
\S表示非空白字符
.点,表示除换行符\n之外其他所有字符

例1:要提取出下面字符串中的acc,aec

import re
a = 'abc,acc,adc,aec,afc,agc'
r = re.findall('a[ce]c', a)  
#元字符[],字符集,出现在[]里的字符是'或'的关系
print(r)
输出:['acc', 'aec']

例2:要提取出下面字符串中非的acc,aec的其他字符

import re
a = 'abc,acc,adc,aec,afc,agc'
r = re.findall('a[^ce]c', a)  #?元字符[^ce]表示非c和e的其他字符
print(r)
#输出:['abc', 'adc', 'afc', 'agc']

例3:要提取出下面字符串中acc,adc,aec,afc这几个中间连续的字符
import re
a = ‘abc,acc,adc,aec,afc,agc’
r = re.findall(‘a[c-f]c’, a) #?元字符[c-f]表示c到f中间所有字符
print®
#输出:[‘acc’, ‘adc’, ‘aec’, ‘afc’]

数量词

1.用{n}表示匹配前一个字符n次,{n,}表示匹配前一个字符n次以上,{n,m}表示匹配前一个字符n到m次

  • 字符集只能以一个字符为元素进行输出

例:

import re
a = 'abc,acc,adc'
r = re.findall('[a-z]',a)
print(r)
#输出:['a', 'b', 'c', 'a', 'c', 'c', 'a', 'd', 'c']

用数量词{numb}输出固定数量长度的单词为一个元素的列表

例:

import re
a = 'abc,acc,adc,aec,afc,agc'
r = re.findall('[a-z]{3}', a)  #?元字符{3}表示匹配前一个字符3次
print(r)
#输出:['abc', 'acc', 'adc', 'aec', 'afc', 'agc']

如果要输出长度不一的单词为一个元素的列表呢

2.用{numb1,numb2}输出长度不一的单词为一个元素的列表

import re
a = 'abcd,acc,ac,apple,afc'
r = re.findall('[a-z]{3,5}', a)  #?{3,5}表示表示匹配前一个字符3-5次
print(r)
#输出:['abcd', 'acc', 'ac', 'apples', 'afc']

思考:匹配3-5次为什么abcd不按照3个单词为一组输出,而是优先输出4个单词呢?

贪婪与非贪婪

默认情况下python以贪婪模式匹配字符串,也就是尽可能多的匹配字符串

非贪婪的模式:{numb}? ------ 在数量词的后面加一个?

r = re.findall('[a-z]{3,5}?', a)
#输出:['abc', 'acc', 'app','les', 'afc'] ------ 注意输出了'les'

3.用’+'输出长度不一的满足条件的所有元素

例:

import re
a = 'abcd,acc,ac,apple,afc'
r = re.findall('[a-z]+', a)  #元字符+表示匹配前一个字符1次以上
print(r)
#输出:['abcd', 'acc', 'ac', 'apple', 'afc']

4.*:匹配前一个字符0次或无限多次

例:

import re
a = 'pytho1python2pythonn3'
r = re.findall('python*', a)  #元字符*表示匹配前一个字符0次或无限多次
print(r)
#输出:['pytho', 'python', 'pythonn']
#注意结果匹配'n'0次或无限多次

5.?:匹配前一个字符0次或1次

例:

import re
a = 'pytho1python2pythonn3'
r = re.findall('python?', a)
print(r)
#输出:['pytho', 'python', 'python']
#注意结果匹配'n'0次或1次
?号经常用于去重的操作 注意区别于非贪婪模式的?

边界匹配符

例:

import re
qq = '100000001'
#如果想要输出4~8位的qq号,用前面的数量词行不行呢
r = re.findall('\\d{4,8}', qq)
print(r)
#输出:['10000000']
#结果并不符合,qq号是100000001,九位,应该剔除在外,但是输出了前八位

用边界匹配符解决

1.用^匹配字符串的开头
2.用$匹配字符串的结尾

import re
qq = '100000001'
r = re.findall('^\\d{4,8}$', qq) 
#一前一后就可以匹配完整的字符串
print(r)
#现在就什么不会输出前几位了,会把字符串当作一个整体来看,不会拆开来了

  • ()分组

例:

import re
a = 'PythonPythonPythonPythonPython'

现在要求判断这样的字符串里面是否包含3个Python

原来的re.findall('Python{3},a)是匹配单个字符n3次
可以用括号()把前面的单词变成一个组,r = re.findall('(Python){3}', a),这就能匹配3个Python

注意区分于中括号[]-----中间是’或’的关系
而圆括号()------中间是’且’的关系

re.findall的三个参数:

(正则表达式pattern,字符串string匹配模式flags)

匹配模式:

re.I:忽略大小写
re.M:多行匹配
re.S:用’.'匹配所有字符,包括换行符
还有好多种,只列举3种

r = re.findall('(python){3}', a, re.I | re.M)
多个匹配模式可以用|分隔

re.S匹配模式演示:

import re
language = 'Python\nPhp\nJava\n'
r = re.findall('python.{1}', language, re.I | re.S)  
#注意正则表达式里的'.'在re.S模式下,代表匹配任意字符,包括换行符
print(r)
#输出:['python\n']

区别于:

import re
language = 'Python\nPhp\nJava\n'
r = re.findall('python.{1}', language, re.I)
print(r)
#输出:[] -------因为在非re.S模式下,'.'匹配的是除了换行符以外的任意字符

re.sub函数

  • 字符串查找并替换

re.sub的五个参数:

(正则表达式pattern,替换后的字符串repl,原字符串string,替换次数count,匹配模式flags)

例:要把Php换成Go

import re
language = 'PythonPhpJavaPhp'
r = re.sub('Php','Go',language,0) 
#count参数默认为0,表示替换将无限进行,即替换所有的Php
print(r)
#输出:PythonGoJavaGo ------注意sub函数不是以列表输出
import re
language = 'PythonPhpJavaPhp'
r = re.sub('Php','Go',language,1) #?count为1,表示只替换一次
print(r)
#输出:PythonGoJavaPhp

re.sub第二个参数可以是一个函数 -------非常常见的一种使用方法

import re
language = 'PythonPhpJavaPhp'
def convert(value):
    matched = value.group()    
    #直接返回value是不行的,调用group内置,返回匹配到的字符串
    return '!' + matched + '!'
r = re.sub('Php',convert,language)
print(r)
#输出:Python!Php!Java!Php!

替换还有一种方式:replace内置函数(算是sub函数的简化版)

import re
language = 'PythonPhpJavaPhp'
language.replace('Php','Go')
print(language)
#报错了,因为字符串是不可变数据类型,要重新赋值才行
import re
language = 'PythonPhpJavaPhp'
language = language.replace('Php', 'Go')  # ?用法:replace
print(language)
#输出:PythonGoJavaGo

把函数作为参数传递

案例一: 在以下的字符串中,找出所有数字,并把所有大于6的数字换成9,所有小于6的数字换成0

import re
a = 'P16Y351T972H168O47N'

def convert(value):
    matched = value.group()

    if int(matched) > 6:
        return '9'
    elif int(matched) == 6:
        return '6'
    else:
        return '0'

r = re.sub('\\d', convert, a)
print(r)
#输出:P06Y000T990H069O09N

match函数与search函数

案例:

import re
a = 'P16Y351T972H168O47N'
r = re.match('\\d', a)
print(r)
r1 = re.search('\\d', a)
print(r1)
#输出:None
      <re.Match object; span=(1, 2), match='1'>

因为match函数只匹配字符串的开始位置,第一个字符不对就直接跳过
search函数匹配整个字符串,输出第一个符合的字符,然后停止匹配

要读取返回的结果,需要使用group方法

print(r1.group())
#输出:1

所以findall函数要远远比这两个函数常用

分组:group函数

案例:要输出lifepython之间的所有字符

import re
s = 'life is short, i use python'
r =re.search('life(.*)python',s)  
#可以思考一下这个正则表达式的含义,这里加不加括号都可以,因为只有一个组
print(r.group())
#输出:life is short, i use python
#不对,连life和python也一起输出了

那怎么输出中间的字符串呢? --------下面的方法在爬虫的过程很像

爬虫抓取html网页要抓取标签中间的部分

import re
s = 'life is short, i use python'
r =re.search('life(.*)python',s)  
#可以思考一下这个正则表达式的含义

print(r.group(1))
#group(1)表示第一个分组,即()内的内容,()里默认是0,匹配的是正则表达式的完整结果
#输出:is short, i use

print(r.groups())  #注意是groups
#输出:(' is short, i use ')

findall函数抓取标签中间的部分,更简单

import re
s = 'life is short, i use python'
r =re.findall('life(.*)python',s)
print(r)    #直接输出'r'就可以
#输出:[' is short, i use ']

再来一个练习:抓取lifepythonpython中间的字符

import re
s = 'life is short, i use python, i love python'
r =re.findall('life(.*)python(.*)python',s)   #?可以使用多个分组
print(r)   #?直接输出'r'就可以
#输出:[(' is short, i use ', ', i love ')]
#或者search函数,print(r.group(1,2))
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值