正则表达式(一)

0、注意事项

1、转义字符是 不是常用的 /

2、^在中括号里面和外面含义不同:在外时,就表示以它后边跟的一个字符开头,如^7[0-9]表示匹配开头是7的,且第二位是任一数字的字符串;如果在中括号里面,表示除了(反选)这个字符之外的任意字符(包括数字,特殊字符),如[^abc]表示匹配除abc之外的其他任一字符。

1、参考

https://www.cnblogs.com/whatisfantasy/p/6014523.html

2、说明

正则表达式是一种用来匹配字符串的强有力的武器。其设计思想是用一种描述性的语言来给字符串定义一个规则,凡是符合规则的字符串,我们就认为它‘匹配’了,否则,该字符串就是不合法的。

比如说,我们用来判断一个字符串是否是合法Email的方法是:

  1、创建一个匹配Email的正则表达式;

  2、用该正则表达式去匹配用户的输入来判断是否合法。

因为正则表达式也是用字符串表示的,所以我们要先了解如何用字符描述字符

3、规则

全规则

1. 任意单字符表示匹配任意对应的字符,如a匹配a,7匹配7,-匹配-。

2. [ ]代表匹配中括号中其中任一个字符,如[abc]匹配a或b或c

3.-在中括号里面和外面含义不同:在时,就匹配它自己;如果在中括号内,表示范围,例如[a-z]表示匹配26个小写字母中的任一个[a-zA-Z]匹配大小写共52个字母任一个[0-9]匹配十个数字任一个

4.^在中括号里面和外面含义不同:在时,就表示以它后边跟的一个字符开头,如^7[0-9]表示匹配开头是7的,且第二位是任一数字的字符串;如果在中括号里面,表示除了(反选)这个字符之外的任意字符(包括数字,特殊字符),如[^abc]表示匹配除abc之外的其他任一字符

5. .表示匹配任意的字符

6. \d表示数字

7. \D表示非数字

8. \s表示由空字符组成,[ \t\n\r\x\f ]。

9. \S表示由非空字符组成,[^\s]。

10. \w表示字母、数字、下划线,[a-zA-Z0-9_]。

11. \W表示不是由字母、数字、下划线组成。

12. 0次或1次

13. + 1次或多次

14. * 0、1或多次

15. {n}  n次

16. {n,m}  n~m次

17. {n,}  n次或n次以上

18. XY表示X后面跟着Y,这里X和Y分别是正则表达式的一部分。

19. X|Y表示X或Y,比如"food|f"匹配的是foo(d或f),而"(food)|f"匹配的是food或f。

20. (X)子表达式,将X看做是一个整体;

各个规则更细致说明,看后边各具体项

3.1、如果直接给出字符,那就是精确匹配

3.2、正则字符

\d:一个数字

\D:非数字

\w:一个字母、数字、下划线

\W:非字母、数字、下划线

\s:一个空格(包含Tab)

\S:非空白字符

\b:匹配一个单词边界(开头、结尾),即匹配内容刚好在边界上,这个边界可以是空格特殊字符

\b前边,则指明是前边界\b后边,则指明是后边界

3.2.1、例子(以下例子都是python语法)

①'00\d'可以匹配'007'但不能匹配'00A'

②'\d\d\d'——'010'

③'\w\w\d'——'py3'

\b的例子

复制代码
ret=[]
re1=re.compile(r'\babc')#abc在开头作为边界
re2=re.compile(r'\bI')  #开头的I作为边界
re3=re.compile(r'abc\b')#abc在结尾作为边界
ret.append(re1.findall('asdas abc 1231231'))
ret.append(re1.findall('asdas*abc 1231231'))
ret.append(re2.findall('I try to Image'))
ret.append(re3.findall('asdasabc*1231231'))
for i in range(len(ret)):
    print (ret[i])

['abc']
['abc']
['I', 'I']
['abc']
复制代码

3.3、:匹配任意字符,除了\n

'py.'——'pyc'、'py2'、'py!'……

这里很容易出错,详见补充④

 

3.4、要匹配变长的字符,在正则表达式中:

*:任意个字符(包含0个)等价于 {0,}

+:至少一个字符 {1,}

:0或1个 {0,1}

{n}:n个字符

{n,m}:n~m个字符

3.4.1、例子

\d{3]\s+\d{3,8}

解读

\d{3}:匹配3个数字,如'010'

\s+:至少一个空格

\d{3,8}:3-8个数字,如'1234567'

综合起来,上面的正则表达式可以匹配任意个空格隔开的带区号的电话号码。

 

如果要匹配'010-12345'呢?由于'-'是特殊字符,在正则表达式中,需要用转义符号'\'转义,所以写法应该是\d{3}\-\d{3,8}

但是仍无法匹配'010 - 12345',因为带有空格,所以我们需要更复杂的匹配方式。

 

3.5、[ ]:表示范围

[0-9a-zA-Z\_]:匹配一个数字、字母或下划线;

[0-9a-zA-Z\_]+:匹配 至少由一个数字、字母或下划线组成的字符串,比如'a100','0_Z','Py3000'……

[a-zA-Z\_][0-9a-zA-Z\_]*:匹配 由字母或下划线开头,后接任一个由数字、字母、下划线组成的字符串,也就是Python合法变量

[a-zA-Z\_][0-9a-zA-Z\_]{0,19}:匹配 由字母或者下划线开头,后接0~19个数字、字母、下划线组成的字符,更精确地限制了字符串的长度为1-20个字符

 [0-3,5-8]:匹配数字(0,1,2,3,5,6,7,8)

注意:

1、元字符在[ ]不再具有特殊意义而是变成了普通字符,但是/d /w /s除外

2、[a-zA-Z]效果等同于[a-z , A-Z] 

[1-35-7]效果等同于[1-3,5-7]

3、[ ]中的^表示反向匹配

[^0-9]:匹配除数字外的字符,相当于\D

 

3.6、A|B:匹配A或B

(P|p)ython ——'Python'或'python'

 

3.7、^:字符串开头

^\d:以数字开头

 

3.8、$:字符串的结尾

\d$:必须以数字结束

^$的结合可以构成整行匹配

^py可以匹配'python'

^py$只能匹配 'py'

 

4、re模块

Python提供了re模块,包含所有正则表达式的功能。由于Python字符串也用'\'表转义,所以可以写字符串时加上r前缀,就不用考虑转义的问题了。(暂时没发现加与不加r前缀的区别,所以此处暂存疑!)(回答是:必须转义的字符必须加,剩下的特殊字符如果无歧义可加可不加)

print('ABC\\-DEF')
ABC\-DEF

print(r'ABC\-DEF')
ABC\-DEF

4.1、match():正则表达式匹配

import re
print(re.match(r'\d{3}\-\d{3,8}$','010-12345'))
print(re.match(r'\d{3}\-\d{3,8}$','010 123456'))

<re.Match object; span=(0, 9), match='010-12345'>
None

匹配成功返回一个Match对象,否则返回None。常用的判断方法是:

test='用户字符串'

if re.match('正则表达式',test):
    print('OK!')
else:
    print('Failed!')

4.2、切分字符串:split()

用正则表达式切分字符串比用固定的字符更灵活。

正常的切分字符串的代码:

'a b   c'.split(' ')
['a', 'b', '', '', 'c']

无法识别连续的空格,我们用正则表达式尝试:

re.split(r'\s+','a b   c')
['a', 'b', 'c']

无论多少个空格都可以正常分割。加入再进行实验

re.split(r'[\s\,]+','a,  ,b,  c')
['a', 'b', 'c']

[\s\,]+:至少有一个空格或者逗号

再加入分号 进行尝试:

re.split(r'[\s\,\;]+','a, ; , ; b   ,,,; ;c')
['a', 'b', 'c']

[\s\,\;]+

如果用户输入了一组标签,可以用正则表达式把不规则的输出转化为正确的数组。

从本例可以看出,如果想把某些不需要的字符从字符串中剔除,只保留剩下的字符,通过构建正则表达式[]+,并将不需要的字符放入其中即可。

 

4.3、分组:group()

除了简单判断是否匹配之外,正则表达式还可以用来提取子串。用( )表示的就是要提取的分组(Group)

比如:

^(\d{3})-(\d{3,8})$分别定义了两个组,可以直接从匹配的字符串中提取出区号和本地号码:

复制代码
m=re.match(r'^(\d{3})-(\d{3,8})$','010-12345')

m
<re.Match object; span=(0, 9), match='010-12345'>

m.group(0)
'010-12345'
m.group(1)
'010'
m.group(2)
'12345'

m.groups()
('010', '12345')
复制代码

如果正则表达式中定义了正则表达式中的一个()对应一个),就可以在Match对象上用group()方法提取出子串来。

group(0)永远是原始字符串,group(1)、group(2)、……表示第1、2、……个子串,此外groups()是一个包含了所有子串tuple

 

另外有一个识别时间的例子:

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-2]|[0-9])-(0[0-9]|1[0-9]|2[0-9]|3[0-1]|[0-9])$'

对于2-304-31这样的非法日期,用正则也识别不了,或者说写出来很困难,这时候就需要程序配合识别了。

 

4.4、贪婪匹配

正则匹配默认是贪婪匹配,也就是匹配尽可能多的字符。举例如下,匹配出数字后边的0:

re.match(r'^(\d+)(0*)$','102300').groups()
('102300', '')

 

由于\d+采用贪婪匹配,直接把后边的0全部匹配了,结果0*只能匹配空字符串了。

必须让\d+采用非贪婪匹配(也就是尽可能少匹配),才能把后边的0匹配出来,加个就可以让\d+采用非贪婪匹配:

re.match(r'^(\d+?)(0*)$','102300').groups()
('1023', '00')

 

4.5、预编译:compile()

当我们在Python中使用正则表达式时,re模块内部会干两件事情:

  1、编译正则表达式,如果正则表达式的字符串本身不合法,会报错

  2、用编译后的正则表达式去匹配字符串

 

如果一个正则表达式要重复使用几千次,出于效率的考虑,我们可以预编译该正则表达式,接下来重复使用时就不需要编译这个步骤了,直接匹配:

复制代码
importre

#编译
re_telephone=re.compile(r'^(\d{3})-(\d{3,8})$')

#使用
re_telephone.match('010-12345').groups()
('010', '12345')
re_telephone.match('010-8086').groups()
('010', '8086')
复制代码

编译后生成Regular Expression对象,由于该对象自己包含正则表达式,所以在调用对应的方法时不用给出正则字符串(如上文中直接调用该对象的match方法)。

 

补充:

①单一类型的字符没必要用[ ],只有当要求匹配不是同一类的多种字符时,才用[ ]

[\w]+完全可以写成\w+

而包含逗号,分号时,就要用[ ],如[\w\,\;]+

②注意转义符号是反斜杠\,而不是斜杠/,这一个小问题经常导致匹配错误又检查不出来!!

③分组总是保存在group(1),group(2)……中,即使筛选时就一个括号(),也要通过group(1)

★④提取网址、邮箱等包含 的字符串时,由于 表示任何字符,所以要想不能匹配到别的网站,必须对.进行转义,即写成\.的形式

比如:163邮箱的提取,要求@前有4-20位

r'^[\w]{4,20}@163.com$' #错误 可能匹配到类似XXX@1633com
r'^[\w]{4,20}@163\.com$'#正确

 重要!!!!!!!

⑤正则串中有多少个括号(),匹配结果的groups中就有几个结果。(即,当你想输出查看匹配项时,你的正则表达式中必须有括号()!)

这样,我们就知道了( )的两个用途:①分组group;②(P|p)

 

两个邮箱匹配的例子

①验证Email地址的正则表达式。

someone@gmail.com √

bill.gates@microsoft.com√

bob#example.com ×

mr-bob@example.com ×

def is_valid_email(addr):
    m=re.compile(r'^[\w\.]+@\w+\.com$')
    if m.match(addr):
        return True
    else:
        return False

②可以提取出带名字的Email地址

<Tom Paris> tom@voyager.org => Tom Paris

bob@example.com => bob

复制代码
def name_of_email(addr):

    m=re.compile(r'^<?([\w\s]+)>?[\w\s]*@\w+\.\w+$')
    #或者
    #m=re.compile(r'^<?(\w+\s*\w*)>?\s*\w*@\w+.\w+$')
    n=m.match(addr)
    return n.group(1)

    
复制代码

 

posted @   ShineLe  阅读(311)  评论(0编辑  收藏  举报
编辑推荐:
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
阅读排行:
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
点击右上角即可分享
微信分享提示