Python实践:Python文本处理之正则表达式

Python实践:Python文本处理之正则表达式


正则表达式是一种用来匹配字符串的强有力的武器,利用 字符来匹配字符的思想,基于显示规则进行模式匹配,可以高效组合成不同样式的字符串,迅速处理字符串。

相信我,学会正则表达式,你在以后的文本处理时,一定会感谢我。温馨提示,建议配合《廖雪峰的Python正则表达式教程》研读,见文末参考资料1。

初级三板斧


基础元字符意义总结如下,日常情况都是以下举例的组合:

  • \d,表示一个数字

  • \w,表示一个字母或数字

  • . , 表示任意一个字符,如:'py.‘可以匹配’pyc’、‘pyo’、'py!'等

  • *, 表示任意个字符(包括0个),对前一个字符模式重复任意次

  • +, 表示至少一个字符

  • ?, 表示0个或1个字符

  • {}, 表示自定义个字符个数,修饰前面一个变量最长的字符个数,如{n}表示n个字符;{n,m}表示n-m个字符,可取到m个字符

  • \s, 表示一个空白符,如空格Space、Tab等,\s+可表示至少有一个空格

组合示例:

  • \d{3,8} ,表示3-8个数字组成的字符串,如’123’或’12345678’
  • \d{3},表示3个数字,如’010’
  • \w.,表示任意一个字符(字符或数字)配一个任意字符, 如’a.', ‘p!’
  • <?[A-Z], 表示可能有0或1个<符号,后面接一个大写字母,如‘<A’,‘A’
  • \s+,表示至少有一个空白符,如’ afb ’

进阶登堂入室


高频问题总结如下:

  • 转义问题,标点符号只有被转义时才匹配自身,否则它们表示特殊的含义。

    • 如:'-_?.',都是特殊字符,在正则表达式中,要用\转义
    • 如:r'py\.',才能查找py.这样的字符串
  • |,选择分支表示或的关系,A|B可以匹配A或B,如(P|p)ython可以匹配’Python’或者’python’。

  • [],表示当前一个字符的范围,大于两种的可能;如:[a-zA-Z\_][0-9a-zA-Z\_]{0, 19},前面1个字符+后面最多19个字符

  • ^,表示行的开头,如^\d,表示必须以数字开头。

  • $,表示行的结束,如\d$,表示必须以数字结束。

  • (),分组功能,(xyz) 字符组,按照确切的顺序匹配字符 xyz。

  • [^],否定字符类。匹配方括号中不包含的任意字符

组合示例:

  • ^(P|p)y,表示首行以P或p开头,第二个字符为y的字符串
  • ^py&,表示整行匹配,行首以p开头,且中间无字符,行尾以y结束
  • [^\w]+ ,表示所有字母或数字的字符串

Python实战


Python用re模块来使用正则表达式功能,原因是正则表达式的英文为“Regular Expression”,常见缩写为:regex 或 regexp。

import re # 导入正则表达式模块

由于Python的字符串本身也用\转义,所以一般使用时要对\本身进行转义,变成\\。比如:

s = 'ABC\\-001' # Python的字符串
# 对应的正则表达式字符串变成:
# 'ABC\-001'

但还有个更优雅的解决办法,强烈推荐:

  • 在字符串前加r,表示按字面意思处理,不转义,可达到相同效果
  • 当然,此时\n,\t,%d等转义字符就无转义功能了
s = r'ABC\-001' # Python的字符串

分割

根据re的split()函数,基于正则表达式的Python字符串分割,说明如下:

  • re.split(r'pattern', 'str')
  • 入参1:匹配pattern,入参2:带查找字符串

实例如下:

# 功能:去除空格等空白符,+表示以上形式的字符至少有一个
re.split(r'\s+', 'a b   c')

# 功能:去除空白符和逗号,+表示以上形式的字符至少有一个
re.split(r'[\s\,]+', 'a,b, c  d')

分组

主要知识点:

  • groups()函数
  • ()的用法,每个()对应分离出一组结果

再以分离识别时间字符串例子进行说明。

t = '19:05:30'
m = re.match(r'^(0[0-9]|1[0-9]|2[0-3]|[0-9])\:(0[0-9]|1[0-9]|2[0-9]|3[0-9]|4[0-9]|5[0-9]|[0-9])\:(0[0-9]|1[0-9]|2[0-9]|3[0-9]|4[0-9]|5[0-9]|[0-9])$', t)
m.groups()  # >>> ('19', '05', '30')

分段理解:

  • (0[0-9]|1[0-9]|2[0-3]|[0-9]),表示识别第一个组,即’19:05:30’中的19
  • 第一组,总体有4种可能形式,用逻辑或|连接
    • 0*
    • 1*
    • 2*
    • *(一位数表示场景)
  • 0[0-9],场景1,表示0字符开头,加一个0-9数字, 00-09
  • 1[0-9],场景2,10-19
  • 2[0-3],场景3,20-23,注意没有24点,因为有00:00
  • [0-9], 场景4,0-9,处理仅一位数的场景

此外,要注意贪心匹配法的问题,以下内容摘自廖雪峰正则表达式文章。

# 默认贪心匹配,即大嘴法,能跟更多的满足条件的组合
>>> re.match(r'^(\d+)(0*)$', '102300').groups()
>>> ('102300', '')

# 必须让\d+采用非贪婪匹配(也就是尽可能少匹配),才能把后面的0匹配出来,加个?就可以让\d+采用非贪婪匹配:
>>> re.match(r'^(\d+?)(0*)$', '102300').groups()
>>> ('1023', '00')

行文至此,细心的读者可能发现,一直都是在处理英文字符,如果要查找中文样式的字符如何处理呢?

正则表达式匹配汉字核心思路是:在unicode编码模式下,汉字编码范围:\u4e00-\u9fa5,可据此进行表征,详细内容见:此文

隋唐练习


来自廖雪峰文章的作业,根据以上知识试解决以下两个问题。

  • 问题1:一个验证Email地址的正则表达式。如以下Email格式:someone@gmail.com;bill.gates@microsoft.com
  • 问题2:提取出带名字的Email地址。如:<Tom Paris> tom@voyager.org => Tom Paris;bob@example.com => bob

参考代码及详解如下:

def is_valid_email(addr):
    # [\w.]+  表示至少有任意一个字母或者数字或者.出现,多个类似数字依然认可
    # 直到遇到@
    # \w+     表示只有字符(字母或数字)出现
    # 直到遇到.com$一直到结尾
    # re_email = re.compile(r'[\w.]+@\w+.com$') # 将正则表达式预编译,以便经常调用
    # if re_email.match(addr):
    if re.match(r'[\w.]+@\w+.com$', addr):
        return True
    else:
        return False

def name_of_email(addr):
    # <?表示可选,若有<则考虑,若无则略过
    # ([A-Za-z\s]+),对以下模式字符串:仅含字母和空格的内容,分组提取到group1
    # (),一个括号表示分一个组
    res = re.match(r'<?([A-Za-z\s]+)>?', addr)
    return res.group(1) # group是个函数,1是入参,表示分组后的第一个结果,0则表示分组前的内容

参考资料


  1. 廖雪峰正则表达式博客,讲解清晰,简明易懂,入门必备:link
  2. 好心人总结的进阶补充手册,概况全面:link
  3. 菜鸟教程,体系化总结:link
  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值