python自主学习——正则表达式

正则表达式

!!!个人主页:个人主页
!!!推荐一款模拟面试、刷题神器,从基础到大厂面试题:点击此处进入牛客网注册学习吧
!!!今日的努力,明日的未来
正则表达式的两个概念:

  1. 源字符串:需要匹配的对象
  2. 匹配模式字符串:匹配模式

正则表达式的特点


  1. 灵活性、逻辑性和功能性非常的强
  2. 可以迅速的用及其简单的方式达到对字符串的复杂控制

正则表达式的特点


正则表达式由一些普通字符和一些元字符组成。普通字符就是我们平时常见的字符串、数字之类的,当然也包括一些常见的符号。而元字符也可以理解为正则表达式引擎中有特殊的意义

字符组


# 用正则表达式判断数字字符,起始就是判断传入字符串中是否含有[]含有的字符
import re
# 一个[]只匹配一位
is_string = lambda astring: re.search('[0123456789]', astring) != None
is_string('aaa12')
import re
is_s = lambda astring:re.search('[Pp]ython',astring)!=None
is_s('hello python3')

re.search()是python提供的正大表达式操作函数,表示“进行正则表达式匹配”;astring是需要判断的字符串。
范围表示法:[x-y]:x到y整个范围内的字符:[0-9]==》[1234567890] [a-z]

[0-9a-zA-Z]表示匹配数字、大写字母或小写字母
[0-9a-fA-F]可以匹配数字、大写形式为a-f,它可以用来验证十六进制字符

字符串的转义


\来转义那些特殊含义的字符,如-

python提供了原生字符串,其非常适合正则表达式:正则表达式是怎样的,完全不需要考虑正则表达式之外的转义(只有双引号字符是例外,原生字符串的双引号字符必须转义写成\")原生字符串的形式是r“string”

字符组简记法


  • \d等价于[0-9],d代表“数字”(digit)
  • \w等价于[0-9a-zA-Z],w代表“单词”word
  • \s等价于\t\r\n\v\f(第二次字符是空格),s表示“空白字符(space)”

注意:字符组简记法中的“单词字符”不止有大小写单词,还包括和下划线_
"空白字符"可以是空格字符、制表符\t,回车符\r、换行符\n等各种“空白字符”

字符组简记法可以单独出现,也可以使用在字符组中,比如[0-9a-zA-Z]也可以写作[\da-zA-Z][^0-9a-zA-Z_]可以写作[^\w]

相对于\d\w\s这三个普通字符组简记法,正则表达式也提供了对应排除型字符组的简记法:\D\W\S——字母完全一样,只是改为大写。这些简记法匹配的字符互补:\s能匹配的字符,\S一定不能匹配;\w能匹配的字符,\W一定不能匹配;\d能匹配的字符,\D一定不能匹配。

利用这种互补的属性,就能得到巧妙的效果:[\s\S][\w\W][\d\D]匹配的就是“所有的字符”(或者叫“任意字符”)。

以非数字开头^\D,以数字结尾\d$

常见量词


  • *,等价于{0,},可能出现,也可能不出现,出现次数没有上限

  • +,等于{1,},至少出现1次,出现次数没有上限

  • ?,等价于{0,1},至多出现一次,也可能不出现

  • .,表示一个字符

    #以er结尾的任意字符 
    .*er$ 
    #匹配URL(以http开头,以/结尾,中间为任意字符)
    ^http\w+\/$
    

    .*er$
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LMnXhetv-1660986072020)(E:\桌面\python\笔记\图片\001.png)]

  • {},表示重复次数,[0-9]{4,6},将[0-9]重复4到6次

使用正则表达式的一条根本规律:使用合适的结构(包括字符组和量词),精确表达自己的意图,界定能匹配的文本

# 匹配电话形式:010-7654321, 0107654321
# 条件:区号为3位,且第一位为0;电话号码部分第一位要非0
^0\d{2}-?[1-9]\d{6}$

# 匹配所有李姓的学生及学号
^李\w+{11}

python中的re模块


  1. re模块中的一些用法:
    • compile创建匹配模式(写正则表达式)
    • match()函数用于查看源(scoure)字符串是否以模式(pattern)字符串开头
    • search()返回第一次成功匹配,如果存在的话
    • findall()返回所有不重叠的匹配,如果存在的话,列表形式来返回,返回的是“(正则表达式)”中字符出现的次数
    • split()会根据pattern将source切片分为若干段,返回这些片段组成的列表
    • sub()需要一个额外的参数,用于替换正则中的字符
source = 'Young Frankenstein'
import re
m = re.search('Frank',source)
print(m.group())
n = re.findall('n.?',source)
print(n)
p = re.split('n',source)
print(p)
q = re.sub('n','?',source)#将n转换成了?
print(q)
#Frank
#['ng', 'nk', 'ns', 'n']
#['You', 'g Fra', 'ke', 'stei', '']
#You?g Fra?ke?stei?
# 找出下列字符中的所有数字
import string
s = string.printable
re.findall('[0-9]',s)
#['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']

import re
result = re.match(r'^travell?er$', 'traveler')
print(result)
result.group()
#<re.Match object; span=(0, 8), match='traveler'>
#'traveler'

pattern = re.compile(r'travell?er')
c = pattern.match('traveller')
c.group()
#<re.Match object; span=(0, 9), match='traveller'>
#'traveller'
### 
#split()按照匹配切分
astring = 'a3b2c1d4e10'

def uncompress(astring):
    a = re.split(r'\d+',astring)[:-1]
    print(a)
    d = re.split(r'[a-zA-z]',astring)[1:]
    print(d)
    return ''.jion([a[i]  * int(d[i]) for i in range(len(a))])

uncompress(astring)

#['a', 'b', 'c', 'd', 'e']
#['3', '2', '1', '4', '10']
#'aaabbcddddeeeeeeeeee'

模式


  • 普通文本值代表自身,用于匹配非特殊字符
  • 使用.代表任意除\n外的字符
  • 使用*表示任意多个字符(包括0个)
  • 使用?表示可选字符
import re
#换行符的匹配
re.search(r'.$','\n') != None
#False
print(re.search(r'.$','.')!= None)
#True
#单行模式
print(re.search(r'(?s)^.$','\n') != None)
#True
#自制“通配字符组”
re.search(r'^[\s\S]$','\n') != None
#True

定义匹配输出


使用match()或search()时,所有的匹配会以MatchObject 对象返回,可以调用其group()方法进行获取匹配的结果。另外,可以使用括号()将某一模式包裹起来,括号里的模式匹配得到的结果归入到自己的group(无名称)中,等到匹配完成后,通过group(num)值类的方法“引用分组”在模式匹配时捕获内容。其中 num 表示对应括号的编号,括号分组的编号规则是从左向右计数,从1开始。调用m.groups()可以得到包含这些匹配的元组

#匹配年月日
astring = '2017-04-07'
m = re.search(r'(\d{4}-(\d{2})-(\d{2}))',astring)
print(m.group(1))
print(m.group(2))
print(m.group(3))
#匹配所有
print(m.group(0))
print(m.group())
#2017
#04
#07
#2017-04-07
#2017-04-07

编号为0的分组他是默认存在的,对应整个表达式匹配的文本。groups()=group(0)

如果正则表达式里包含嵌套的括号,其括号的编号将以这种方式定义:无论括号如何嵌套,分组编号都是根据开括号出现的顺序来计数的;开括号是从左向右数起第多少个开括号,整个括号分组的编号就是多少

 (((\d{4})-(\d{2}))-(\d{2}))
0---------------------------
1---------------------------
 2-----------------
  3-------
          4-------
                   5-------
import re
m = re.search(r'(((\d{4})-(\d{2}))-(\d{2}))','2017-04-07')
print(m.group())
print(m.group(0))
print(m.group(1))
print(m.group(2))
print(m.group(3))
print(m.group(4))
print(m.group(5))
#2017-04-07
#2017-04-07
#2017-04-07
#2017-04
#2017
#04
#07

命名空间


( ?Pexpr ) 会匹配exer,并将匹配结果存储到储存名为name的组中。命名分组捕获仍然保留了数字编号

import re
m = re.search(r'(?P<year>\d{4})-(?P<mouth>\d{2})-(?P<day>\d{2})','2017-04-07')
print(m.group())
#2017-04-07
print(m.group(0))
#2017-04-07
#以元组形式去输出
print(m.groups())
#('2017', '04', '07')
print(m.group(1))
#2017
print(m.group('year'))
#2017
print(m.group(2))
#04
print(m.group('month'))
#04
print(m.group(3))
#07
print(m.group('day'))
#07

正则表达式


分组捕获的文本,不仅仅用于数据提取,也可以用于替换,比如对于上面的例子,希望将YYY-MM-DD格式的日期装变为MM/DD/YYYY,就可以使用正则表达式替换(re.sub())

反向引用


[a-z][a-z]
''重叠出现‘的字符,取决于与第一个[a-z]在运行时匹配的结果,而不能预先设定,即必须知道之前匹配的确切内容

反向引用允许在正则表达式内部引用之前的捕获分组匹配的文本(左侧),其形式也是\num,其中num表示所引用分组的编号,编号规则与之前介绍的相同

re.search(r'^([a-z])\1$', 'aa') != None  # => True
re.search(r'^([a-z])\1$', 'ac') != None  # => False

具有二义性的反向作用:

re.sub(r'(\d)', r'\10', '123')
# error: invalid group reference 10 at position 1

Python提供了\g表示法,将\10写成\g<1>0,这样就避免了替换时无法使用\0的问题。

re.sub(r'(\d)', r'\g<1>0', '123')
#'102030'

命名分组的引用方法
如果使用了命名分组,在表达式中反向引用时,必须使用(?P=name)的记法。而要进行正则表达式替换,则需要写作\g<name>其中name是分组的名字

re.search(r'^(?P<char>[a-z])(?P=char)$', 'aa') != None  # => True

re.sub(r'(?P<digit>\d)', r'\g<digit>0', '123')  # => '102030'

Python提供了\g表示法,将\10写成\g<1>0,这样就避免了替换时无法使用\0的问题。

re.sub(r'(\d)', r'\g<1>0', '123')
#'102030'

命名分组的引用方法
如果使用了命名分组,在表达式中反向引用时,必须使用(?P=name)的记法。而要进行正则表达式替换,则需要写作\g<name>其中name是分组的名字

re.search(r'^(?P<char>[a-z])(?P=char)$', 'aa') != None  # => True

re.sub(r'(?P<digit>\d)', r'\g<digit>0', '123')  # => '102030'

正则表达式细节化网站

正则表达式


版权声明:本文为qq_51142828原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。