Python随记(30.1)正则表达式的基本使用

正则表达式:按照一定的规则,从某个字符串中匹配出想要的数据,这个规则就是正则表达式。这在其他语言中都是可以使用的。

单字符串匹配规则
字符含义举例
字符名匹配某个字符串ret = re.match(‘a’,‘abc’) print(ret.group()) >>>a 从最开始查找没有匹配就报错
.点,匹配任意字符除了(\n)ret = re.match(’.’,’+bc’) print(ret.group()) >>>a+ text= ‘\nabc’ # 报错
\d匹配任意的数字
\D匹配任意的非数字
\s匹配空白字符(\n,\t,\r,空格)ret = re.match(’\s’,’\nab’)
\S匹配非空白字符
\w匹配 a-z A-Z以及数字和下划线ret = re.match(’\w’,’_ab’)
\W与上一个相反
[]组合方式被他包裹的元字符都会失去特殊功能,将里面的内容看作普通字符(除了 - 小横杆,反斜杠,脱字符)。

需要注意的一点是:元字符在方括号中不会触发“特殊功能”,在字符类中,它们只匹配自身。例如 [akm$] 会匹配任何字符 ‘a’,‘k’,‘m’ 或 ‘$’,’$’ 是一个元字符,但在方括号中它不表示特殊含义,它只匹配 '$'字符本身。
对于点这个元字符,如果设置了 re.DOTALL 标志,. 将匹配包括换行符在内的任何字符。

import re

#[]组合方式
ret = re.match('[1b]','bb')
print(ret.group())  >>>b  # 匹配第一个字符,是否是 1 或 b
# 通过组合的方式实现\d:
ret = re.match('[0-9]','0ab')
print(ret.group())  >>>0

ret = re.match('[^0-9]',text)  # 取反,去0-9以外所有字符

ret = re.match('[a-zA-z0-9_]',text)

多字符匹配

字符匹配
*匹配前一个字符0次或无限次
+匹配前一个字符一次或无限次
匹配前一个字符0次或1次
{m}/{m,n}匹配前一个字符m 次到n次
*?/ +?/??匹配模式变为非贪婪(尽可能少匹配字符)
# *  0个或多个字符
text = 'abc'
ret = re.match('\w*',text)
print(ret.group())   >>>abc  # text = '+bc' 返回一个空字符串

# + 一个或多个
ret = re.match('\w+','+abc')
print(ret.group())  # 报错

# ? 0个或一个 要是英文的
ret = re.match('\w?','0ab')
print(ret.group())  >>>0   # text='+bc' 返回一个空字符串

# {m} m 个
ret = re.match('\w{2}','0ab')
print(ret.group())  >>>0a

# {m,n} 匹配m-n之间的个数
ret = re.match('\w{1,3}','1+0ab')
print(ret.group())  >>>1

验证手机号之类的案例

  • 验证手机号码: 手机号码的规则是1开头,第二位可以是34567,后面九位随意
    text = ‘15757575577’
    ret = re.match(‘1[34567]\d{9}’,text)
    print(ret.group()) >>> 15757575577
  • 验证邮箱:名称用数字,英文字符,下划线组成,然后@符号,后面是域名
    ret = re.match(’\w+@[a-z0-9]+\.[a-z]+’,‘AIlumanman@haha.com’) # .com这个点前面加个转义字符
  • 验证url http https ftp 加上一个冒号,加上一个斜杠,后面就是任意非空白字符。
    ret = re.match(’(http|https|ftp): //\s+’,‘https://editor.csdn.net/md?articleId=105305539’)
    (又发现莫名其妙的表情了)😕
  • 验证身份证 总共18位,前17是数字,后一位可以是数字,x,X
    ret = re.match(’\d[17][\dxX]’,‘123456789123456789’)
开始结束和非贪婪
# ^脱字符 以。。。开头
ret = re.search('^hello','hello world')   # match方法已经相当于有了 ^,search搜索全部
print(ret.group())   >>>hello

# $ 以。。。结尾
ret = re.search('world$','hello world')   
print(ret.group())   >>>world
ret = re.search('^$','')   # ^$ 匹配空字符串

# | 匹配多个字符串或表达式
ret = re.match('(http|https|ftp)://\S+','http://baidu.com')

# 贪婪和非贪婪
ret = re.search('\d+?','12345')
print(ret.group())  >>>1  # 一般默认是贪婪模式,加上?后变成非贪婪,尽量匹配少的字符
  • 提取HTML标签名案例:
text = <h1>我是标签<h1>
ret = search('<.+?>',text)     # 要使用非贪婪模式
print(ret.group())  >>>h1
  • 验证一个字符是不是0-100 之间的数字
    0-100 四种类型:0(排除01 02 这样的情况),一位数,两位数,三位数
    re.match(‘0$ | [1-9]\d?$|100$’,text)
    [1-9]\d? 可以代表一位两位数的情况,?就是可以有也可以没有。
    0$ 为了避免01这样的错误数字被匹配,必须以0结尾。也不能用search方法,否则只要有非零数字就会被匹配
    [1-9]\d? 符号$ 是为了防止100被匹配前两位,以两位数结尾。
    100$ 符号$ 防止匹配出1000之类的
转义字符,原生字符
text = 'apple pritce is $99,range pritce is $88'  # 提取 $ 后面的数据
ret  = re.findall('$\d+',text)
print(ret) # findall返回的是字典,直接打印就好,但是返回的是个空列表
# 因为$ 有本身的含义,所以无法在text 中匹配,所以可以用转义字符,原生字符
ret  = re.findall('\$\d+',text)

text = '\cba'
ret = re.match('\c',text)  # 这肯定会报错的,正则会将\与c 结合判断是否有特殊意义。
# 但是写成 \\c 还是会报错,这是因为这个解析需要解析两次,一次在python层面,再将结果进行正则层面的解析,又会将\and c结合。
# 所以要在正则层面出现两个斜杠,在python层面要出现三个。。所以我选择原生字符,这样python层面就不会在解析了
ret = re.match(r'\\c',text)
# 所以以后写正则时,多用原生字符

另外,转义字符也有其他作用:

  • 对子组的引用:re.search(r'(love)\1','lovelove') 这里的\1表示引用前面序号为1 的子组(也就是第一个子组),所以相当于re.search(r'lovelove','lovelove')注意,在 Python 的字符串中会使用反斜杠加数字的方式来表示数字的值对应的 ASCII 字符,所以在使用反向索引的正则表达式中,我们依然强调要使用原始字符串。
  • 如果反斜杠后面跟着也0开头或三位的数字,那会把这三位数字作为一个八进制数来看待。找对应的ASCII码就好
分组
text = 'apple pritce is $99,range pritce is $88'
ret = re.search('.+\$\d+,.+\$\d+',text)
print(ret.group())  # 会获得整个字符, 要单独获得$ 后面的数字,就可以使用分组

ret = re.search('.+(\$\d+),.+(\$\d+)',text)
print(ret.group(1)) >>> $99 匹配第一个分组
print(ret.group(2)) # 匹配第二个
# group()/group(0)  匹配整个字符串
# groups() 匹配所有分组
# group() 方法可以一次传入多个子组的序号:
print(ret.group(1,2)

子组的索引值是从左到右进行编号,子组也允许嵌套,因此我们可以通过从左往右来统计左括号 ( 来确定子组的序号。

>>> p = re.compile('(a(b)c)d')
>>> m = p.match('abcd')
>>> m.group(0)
'abcd'
>>> m.group(1)
'abc'
>>> m.group(2)
'b'
常用函数
  1. search()方法用于在字符串中搜索正则表达式模式第一次出现的位置。返回<re.Match object; span=(0, 1), match='a'>
  • 可以使用print(ret.group())只返回match的内容。
  • start() 返回匹配的开始位置 # match() 只检查正则表达式是否在字符串的起始位置匹配,所以 start() 总是返回 0
  • end() 返回匹配的结束位置
  • span() 返回一个元组表示匹配位置(开始,结束
  1. findall查找所有满足条件的,并返回一个列表。如果给出的正则表达式包含了一个或多个子组,就会返回子组中匹配的内容,如果存在多个子组,将匹配的内容以元组的形式返回。
  2. finditer() 需要在返回前先创建一个列表,而 finditer() 则是将匹配对象作为一个迭代器返回,如果列表很大,那么返回迭代器的效率要高很多
  3. sub 根据规则替换其他字符串
text = 'ni hao,a'
new_text = re.sub(r' |,','\n',text)  # 使用replace的话,对多种替换对象要替换多次

案例:

html = '''
<ol>
    <li><p>编程时具有<strong>语法高亮</strong>、<em>缩进</em>、<em>tab补全</em>的功能。</p></li>
    <li><p>可直接通过浏览器运行代码,同时在代码块下方展示运行结果。</p></li>
    <li><p>以富媒体格式展示计算结果。富媒体格式包括:HTML,LaTeX,PNG,SVG等。</p></li>
    <li><p>对代码编写说明文档或语句时,支持Markdown语法。</p></li>
    <li><p>支持使用LaTeX编写数学性说明。</p></li>
</ol>
'''
new_html = re.sub('<.+?>','',html)
print(new_html)
>>>
    编程时具有语法高亮、缩进、tab补全的功能。
    可直接通过浏览器运行代码,同时在代码块下方展示运行结果。
    以富媒体格式展示计算结果。富媒体格式包括:HTML,LaTeX,PNG,SVG等。
    对代码编写说明文档或语句时,支持Markdown语法。
    支持使用LaTeX编写数学性说明。

subn() 方法跟 sub() 方法干同样的勾当,但区别是返回值为一个包含有两个元素的元组:一个是替换后的字符串,一个是替换的数目。
4. split 根据规则分割字符串,如果使用了捕获组,那么作为分隔符的值也会被返回

text = 'ni hao,a'
ret = re.split(r' |,',text)
print(ret)       >>>['ni', 'hao', 'a']

>>> re.split(r'( |,)',text)
['ni', ' ', 'hao', ',', 'a']
  1. compile 编译正则表达式
    其实正则的运行是要跟C一样要先编译的,我们可以先进行编译,在多次提取的时候以提升效率
text = 'apple price is 999.999'
r = re.compile('\d+\.?\d*')   # r 是已经编译好的了
ret = re.search(r,text)
print(ret.group())
  1. 对正则做注释(毕竟超级复杂不是)
    在后面加一个 re.VERBOSE
text = 'apple price is 999.999
r = re.compile('''
\d+      # 整数部分
\.?	  # 小数点
\d*		# 小数部分
''',re.VERBOSE)   
ret = re.search(r,text)
print(ret.group())
对贪婪模式过程的补充

我们通过例子一步步的给大家讲解什么叫“贪婪”:先考虑一下表达式 a[bcd]*b,首先需要匹配字符 ‘a’,然后是零个到多个 [bcd],最后以 ‘b’ 结尾。那现在想象一下,这个 RE 匹配字符串 abcbd 会怎样?

步骤匹配说明
1a匹配 RE 的第一个字符 ‘a’
2abcbd引擎在符合规则的情况下尽可能地匹配 [bcd]*,直到该字符串的结尾
3失败引擎尝试匹配 RE 最后一个字符 ‘b’,但当前位置已经是字符串的结尾,所以失败告终
4abcb回退,所以 [bcd]* 匹配少一个字符
5失败再一次尝试匹配 RE 最后一个字符 ‘b’,但字符串最后一个字符是 ‘d’,所以失败告终
6abc再次回退,所以 [bcd]* 这次只匹配 ‘bc’
7abcb再一次尝试匹配字符 ‘b’,这一次字符串当前位置指向的字符正好是 ‘b’,匹配成功

最终,RE 匹配的结果是 abcb。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值