python--正则表达式

2017-11-21  本文已影响0人  缓慢移动的蜗牛

如果不知道正则表达式是什么,可以看一下此篇入门文章
关于正则中的表达式符号和特殊字符,可以看此速查表,部分内容与python的扩展写法有些出入
自己写的正则表达式,也可以用此工具校验一下
python中的一些扩展写法,和速查表的内容有出入的

扩展写法.png 常见的正则表达式属性.png

该文章所使用的python版本为3.5.2


在python中,是使用re模块来支持正则表达式的,使用该模块时,直接引入即可

import re

  • match()函数试图从字符串的起始部分对模式进行匹配
  • search()的工作方式与 match()完全一致,不同之处在于 search()会用它的字符串参数,在任意位置对给定正则表达式模式搜索第一次出现的匹配情况。如果搜索到成功的匹配,就会返回一个匹配对象; 否则, 返回
m = re.match('foo', 'foo')
if m: print(m.group())  #  输出为: foo

m = re.match('foo', 'seafood')  # match只能从起始字符串开始匹配的,所以返回m的值为None

m = re.search('foo', 'seafood')
if m: print(m.group())  #  输出: foo

  • findall()查询字符串中某个正则表达式模式全部的非重复出现情况,返回的是一个list
  • finditer()与findall()类似,不过返回的是一个迭代器而已
s = 'This and that. the and thirty'
print(re.findall(r'(th\w+) and (th\w+)', s, re.I))  #  输出: [('This', 'that'), ('the', 'thirty')]

  • 这两个函数是用于实现搜索和替换功能
  • subn()和 sub()作用一样,sub()返回替换后的字符串,但 subn()还返回一个表示替换的总数,替换后的字符串和表示替换总数的数字一起作为一个拥有两个元素的元组返回。
ret = re.sub('X', 'Mr.Smith', 'attn: X\n\nDear X, \n')
print(ret)  #  'attn: Mr.Smith\n\nDear Mr.Smith, \n'

ret = re.subn('X', 'Mr.Smith', 'attn: X\n\nDear X, \n')
print(ret)  #  ('attn: Mr.Smith\n\nDear Mr.Smith, \n', 2)

e 模块和正则表达式的对象方法 split()对于相对应字符串的工作方式是类似的,但是与分割一个固定字符串相比,它们基于正则表达式的模式分隔字符串,为字符串分隔功能添加一些额外的威力

DATA = (
    'Mountain View, CA 94040',
    'Sunnyvale, CA',
    'Los Altos, 94023',
    'Cupertino 95014',
    'Palo Alto CA',
)
for datanum in DATA:
    s = re.split(', |(?= (?:\d{5}|[A-Z]{2})) ', datanum)  # 依据城市名或者编码拆分,正则的含义:依据", "(逗号空格)拆分或者依据空格(该空格的左侧是5个数字或者是2个大写字母)
    print(s)

结果:
['Mountain View', 'CA', '94040']
['Sunnyvale', 'CA']
['Los Altos', '94023']
['Cupertino', '95014']
['Palo Alto', 'CA']

简单的邮箱地址匹配

patt = '\w+@(\w+\.)?\w+\.com'  # 只能匹配@后面,类似于xxx.com/xxxx.yyy.com的邮箱
m = re.match(patt, 'nobody@xxx.yyy.com')

patt = '\w+@(\w+\.)*\w+\.com'  # 匹配@后面有多个域名的邮箱,类似xxx.xxx.xxx.xxx...com
m = re.match(patt, 'nobody@xxx.yyy.zzz.com')

group()函数的一些示例

re.match('(ab)', 'ab')  # group()==group(1) 相等
re.match('(a)(b)', 'ab') # group():ab  group(1):a  group(2):b
re.match('(a(b))', 'ab') # group():ab  group(1):ab group(2):b
re.match('((a)(b))', 'ab') # group():ab  group(1):ab  group(2):a goup(3):b

m = re.search(r'\bthe', 'bite the dog')  # \b匹配的是单词边界
m = re.search(r'the\b', 'bitethe dog')
m = re.search(r'\Bthe', 'bitethe dog')  # 匹配左侧没有边界的the

使用re.x编写易于查看的正则表达式

# 编写易于查看的正则表达式
# re.X/VERBOSE 标记非常有趣;该标记允许用户通过抑制在正则表达式中使用空白符(除了在字符类中或者在反斜线转义中)来创建更易读的正则表达式
m = re.search(r'''(?x)
\((\d{3})\)
[ ]
(\d{3})
-
(\d{4})
''', '(800) 555-1212')  # 其实和这个等价了m = re.search(r'\((\d{3})\)[ ](\d{3})-(\d{4})','(800) 555-1212'),但是更易于看

# 还可以使用\N,其中 N 是在替换字符串中使用的分组编号
# 将 2/20/91  换成  1991-02-20
m = re.sub(r'(\d{1,2})/(\d{1,2})/(\d{2}|\d{4})', r'19\3-0\1-\2', '2/20/91')

指定group()分组的名称

# (?P<name>) 和 (?P=name)
# 前者通过使用一个名称标识符而不是使用从 1 开始增加到 N 的增量数字来保存匹配,
# 如果使用数字来保存匹配结果,我们就可以通过使用\1,\2 ...,\N \来检索,  可以查看上一个示例
# 大概意思就是: 原来的分组,默认的用group(1),group(2)...去取结果,现在用group('xxx')去取
m = re.search(r'\((?P<areacode>\d{3})\) (?P<prefix>\d{3})-(?:\d{4})', '(900) 555-1212 abc (600) 666-9898')
print(m.groupdict())  # 输出: {'areacode': '900', 'prefix': '555'}
print(m.group())  # 输出: (900) 555-1212
print(m.group(1), m.group('areacode'))  # 输出:900 900

m = re.sub(r'\((?P<areacode>\d{3})\) (?P<prefix>\d{3})-(\d{4})', r'\g<areacode> \g<prefix>-xxxx', '(900) 666-1212')
print(m)  # 输出: 900 666-xxxx
m = re.sub(r'\((?P<areacode>\d{3})\) (?P<prefix>\d{3})-(\d{4})', r'\1 \2-xxxx', '(900) 666-1212')  # 与上面的等价
print(m)

指定分组名,并且易于查看的正则表达式

# 下面这种写法,太长,看着太费劲
m = re.match(
    r'\((?P<areacode>\d{3})\) (?P<prefix>\d{3})-(?P<number>\d{4}) (?P=areacode)-(?P=prefix)-(?P=number) 1(?P=areacode)(?P=prefix)(?P=number)',
    '(800) 555-1212 800-555-1212 18005551212')
print(bool(m))
# 使用(?x)优化
m = re.match(r'''(?x)
# 匹配 (800) 555-1212
\((?P<areacode>\d{3})\)[ ](?P<prefix>\d{3})-(?P<number>\d{4})

# 匹配空格
[ ]

# 匹配 800-500-1212
(?P=areacode)-(?P=prefix)-(?P=number)

# 匹配空格
[ ]

#匹配18005551212
1(?P=areacode)(?P=prefix)(?P=number)
''', '(800) 555-1212 800-555-1212 18005551212')
print(bool(m))

一串数字,每三个之间加上一个分隔符

# 给一串数字,每三位添加一个'-'
data = '1234567890'
patt = r'((?<=\d)\d{3})+\b'
m = re.search(patt, data)
while m:
    data = data[:m.start()] + '-' + data[m.start():]
    m = re.search(patt, data)
print('添加"-"完毕,结果为:', data)

识别时间

# 左边不能是数字,右边也不能是数字
patt = r'(?<!\d)(2[0-3]{1}|[01]?[0-9]{1}):([0-5]?[0-9]{1}):([0-5]?[0-9]{1})(?!\d)'
m = re.search(patt, 'asc 19:23:23 adfs')
print(m.group(1), m.group(2), m.group(3))
上一篇 下一篇

猜你喜欢

热点阅读