【Python知识点补充】正则表达式(一)

参考书籍:https://github.com/ziishaned/learn-regex/blob/master/translations/README-cn.md

以及https://blog.csdn.net/findingxu/article/details/91526471

使用python来验证正则表达式的方法:

基本用法

var x = "abcda";
//两个参数都是字符串
var y = x.replace('a','x');//'xbcda'
进阶用法

var x = "abcda";
//前面参数使用正则,后面使用字符串
var y = x.replace(/a/g,'x');//'xbcdx'
复杂用法

var x = 'abcda';
//前面参数使用正则,后面使用字符串
var y = x.replace(/a/g,function(match){
  return match.toUpperCase();
});//'AbcdA'

 

 

 

实验代码如下:

import re
m = re.search('[a-z]', 'bcdef')
print(m.group(0))

如果用r',就用findall
import re
m = re.findall(r'\bbc\b', 'abc abcde bc bcd')
print(m[0])

基本理解的知识点:(参考上边网址的)

"""
### 常用元字符 ###
1 .:匹配任何一个字符;
2 ^:匹配除去所列首个字符外的所有字符; ^\d表示必须以数字开头。
3 $:匹配字符串的尾部字符  \d$表示必须以数字结束
4 []:由一对方括号括起来的字符,表明一个字符集合,能够匹配包含在其中的任意一个字符。’-‘ 减号来指定一个字符集合的范围。例子:[a-zA-Z][^a-zA-Z]
5 | 将两个规则并列起来,注意是匹配两边所有的规则 
    要匹配 ‘I have a dog’或’I have a cat’,需要写成r’I have a (?:dog|cat)’ ,而不能写成 r’I have a dog|cat’
5 (?: )  如果想限定它的有效范围,必需使用一个无捕获组 ‘(?: )’包起来
6 \d  匹配数字,这是一个以’\’开头的转义字符,’\d’表示匹配一个数字,即等价于[0-9]
7 \D 匹配非数字 这个是上面的反集,即匹配一个非数字的字符,等价于[^0-9]。注意它们的大小写
   下面我们还将看到Python的正则规则中很多转义字符的大小写形式,代表互补的关系。
8 \w 匹配字母和数字 匹配所有的英文字母和数字,即等价于[a-zA-Z0-9]。 \W  等价 [^a-zA-Z0-9]
9 \s 匹配间隔符  即匹配空格符、制表符、回车符等表示分隔意义的字符,它等价于[ \t\r\n\f\v]。(注意最前面有个空格)  补集:  \S 
10 \A 匹配字符串开头  匹配字符串的开头。它和’^’的区别是,’\A’只匹配整个字符串的开头,即使在’M’模式下,它也不会匹配其它行的行首。
11 \Z 匹配字符串结尾  匹配字符串的结尾。它和’$’的区别是,’\Z’只匹配整个字符串的结尾,即使在’M’模式下,它也不会匹配其它各行的行尾。
12 \b’ 匹配单词边界  它匹配一个单词的边界,比如空格等,不过它是一个‘0’长度字符,它匹配完的字符串不会包括那个分界的字符。
       而如果用’\s’来匹配的话,则匹配出的字符串中会包含那个分界符
13 \B 匹配非边界 它同样是个0长度字符。re.findall( r’\Bbc\w+’ , s )     #匹配包含’bc’但不以’bc’为开头的单词
    ['bcde']  #成功匹配了’abcde’中的’bcde’,而没有匹配’bcd’
14 (?# ) 注释 Python允许你在正则表达式中写入注释
### 重复 规则 ###
15 *   0或多次匹配  
16 +  1次或多次匹配  表示匹配前面的规则至少1次,可以多次匹配
17 ?  0或1次匹配 只匹配前面的规则0次或1次
### 精确匹配和最小匹配  ###
18 {m}    精确匹配m次
   {m,n}  匹配最少m次,最多n次。(n>m)  指定最少3次:{3,}  最大为5次:{,5}
    例子: re.findall( r’\b\d{3}\b’ , s )            # 寻找3位数
19 ‘*?’ ‘+?’ ‘??’ 最小匹配
   ‘*’ ‘+’ ‘?’通常都是尽可能多的匹配字符(贪婪匹配)。有时候我们希望它尽可能少的匹配。
   #例子 re.match(r'^(\d+)(0*)$', '102300').groups()  #('102300', '') 
   #     re.match(r'^(\d+?)(0*)$', '102300').groups() #('1023', '00')
   
### 前向界定与后向界定 ###
20 (?<=…) 前向界定  括号中’…’代表你希望匹配的字符串的前面应该出现的字符串。
    前向界定括号中的表达式必须是常值,也即你不可以在前向界定的括号里写正则式
    re.findall( r’(?<=[a-z]+)\d+(?=[a-z]+)' , s )          # 错误的用法
21 (?=…)  后向界定
   不过如果你只要找出后面接着有字母的数字,你可以在后向界定写正则式:
   re.findall( r’\d+(?=[a-z]+)’, s )
22 (?<!...) 前向非界定
只有当你希望的字符串前面不是’…’的内容时才匹配
23 (?!...) 后向非界定
只有当你希望的字符串后面不跟着’…’内容时才匹配。
### 使用组 ###
24  ()    包含在’()’中的内容,而虽然前面和后面的内容都匹配成功了,却并不包含在结果中,
    用group()或group(0)返回匹配的所有结果,用 group(1),(2)...返回第1,2...个()里面的内容
25  (?(id/name)yes-pattern|no-pattern) 判断指定组是否已匹配,执行相应的规则
    这个规则的含义是,如果id/name指定的组在前面匹配成功了,则执行yes-pattern的正则式,否则执行no-pattern的正则式。
    
### 注意 ### 
碰到字符串里面有以上的符号的或者像是 _ - 等字符  要加转义符 \
"""

实例代码第一单元:"."、"+"、"^"、“[]”、“$”、“-”

import re
 
p1 = '.+'
#  "."匹配任何一个字符,"+"匹配1次或多次匹配  表示匹配前面的规则至少1次,可以多次匹配,这句话含义就是一次或者多次匹配任意一个字符
p2 = '[^bc]'
#  "^"匹配除去所列首个字符外的所有字符,"[]"由一对方括号括起来的字符,表明一个字符集合,能够匹配包含在其中的任意一个字符,“[]”只返回一个字符。“[^bc]”表示返回除b和c字符串中的第一个字符
p3 = '[ab$]'
#  "$"匹配字符串的尾部字符,'ab$'返回一个以ab结尾的字符串,如果加上一个[],只返回字符串的第一位,ab的第一位是a,所以只返回a。
p4 = '[a-z]'
#  “-” 减号来指定一个字符集合的范围,a-z表示小写字母都行,常见的还有a-zA-Z0-9,如果加上一个[],只返回字符串的第一位
string = 'abc'
m = re.match(p1,string)
#结果是 abc
n = re.match(p2,string)
#结果是 a
l = re.match(p3,string) 
#结果是 a
o = re.match(p4,string)
#结果是 a

实例代码第二单元:

# 解析网页  HTML  <html><body><h1>hello world<h1></body></html>
import re
 
key = r"<html><body><h1>hello world<h1></body></html>"
p1 = r"(?<=<h1>).+?(?=<h1>)"
# "()" 是为了提取匹配字符串的,表达式中有几个()就有几个相应的匹配字符串
# "?" 是威力0或1次匹配 只匹配前面的规则0次或1
#(?<=…) 前向界定  括号中’…’代表你希望匹配的字符串的前面应该出现的字符串。向前边希望出现<h1>
#(?=…)  后向界定  括号中’…’代表你希望匹配的字符串的后面应该出现的字符串。向后边希望出现</h1>
pattern1 = re.compile(p1)
matcher1 = re.search(pattern1,key)
print(matcher1.group(0)) # hello world

实例代码第三单元:


s1 =  'abc abcde bc bcd'
#\b’ 匹配单词边界  它匹配一个单词的边界,比如空格等,不过它是一个‘0’长度字符,它匹配完的
#字符串不会包括那个分界的字符。
#(而如果用’\s’来匹配的话,则匹配出的字符串中会包含那个分界符)
#\b的理解可以参考网址https://www.cnblogs.com/softidea/p/4925577.html。可以这样理解,\b只看前边
#比如第一个\b前边什么都没有代表着,前边是空格,以空格为开头,后边跟个b,代表着字符串以b为开始,第二个#\b前边有一个c,后边什么都没有代表着以c为结尾。/b类似于边界,可以用作单独的一个开始和结尾,或者两者都用,但不能用在匹配字符串中间,比如'a\bnice'。
print(re.findall( r'\bbc\b', s1 )) 
#结果 [bc]
#如果用r'就用findall函数

实践代码第四单元:

import re
s2 = 'aaa bbb111 cc22cc 33dd'
#  "[a-z]":其中"a-z"是指小写字母,"[]"是指从匹配的字符中任选一个,合起来就是匹配出一个小写字母。
#  "\b[a-z]":以一个小写字母开头
#  "+":1次或多次匹配  表示匹配前面的规则至少1次,可以多次匹配.
#  "\d":是指匹配数字,这是一个以’\’开头的转义字符,’\d’表示匹配一个数字,即等价于[0-9]
#  "*":是指出现0次或者多次
#  "+\d*\b":指的是出现或不出现一个或者连续数字结尾
#  很明显有两个\b代表着是一个完整的字符组,前边和后边都是空格或者单独的字组。
#  正则表达式可以分为三部分理解一部分是"\b[a-z]"代表开头,一部分是"\d*\b",代表结尾,一部分"*"是中间出现一次以上。
#  整体意思就是至少以字母开头,出现或不出现以一个或者多个连续的数字结尾的单独字符组
#  元字符"+"和"*"作用的对象都是字符前边的字母
re.findall( r'\b[a-z]+\d*\b' , s2 )  
#结果 "aaa"和"bbb111" 

实践代码第五单元:

import re 
s3 =  '123 10e3 20e4e4 30ee5'
#元数组在正则表达式中有分组的功能:
# “\b\d+”代表第一个单元,意思是以一个或者多个数字开头
# "?":是指"0或1次匹配 只匹配前面的规则0次或1次
# "[eE]?"代表第二个单元,意思是e或者E出现任意一个的概率是0或则一次,要么不出现,要么出现一次。
# "*":是指0或多次匹配
# "\d*\b"代表第三单元,意思是匹配字符串的结尾是多个数字或者没有数字
re.findall( r'\b\d+[eE]?\d*\b' , s ) 
# 结果是'123', '10e3'

实践代码第六单元:

import re
s4  = '/* part 1 */ code /* part 2 */' 
#  如果要查找元字符,比如"/"或者“*”,需要不能直接匹配,需要用"\"转义一下,比如\和*,使用\\和\*
#  "."匹配任意字符 "*"出现0次或多次 "?"出现0次和一次
#  这个正则表达式可以分成3个部分,首尾的“/\*”和“\*/”是两部分都代表以/*为首,以*/为尾。
#  另一部分是.*?代表任意字符可连续,可连续可不连续。总之就是任意字符
#  很多python链接筛选器中会用到.*?
re.findall(r'/\*.*?\*/',s4) 
#  结果 '/* part 1 */ 和 /* part 2 */


re.findall( r'(?<=/\*).+?(?=\*/)',s4)
#  "(?<=…)" 前向界定  括号中’…’代表你希望匹配的字符串的前面应该出现的字符串。
#  "(?=…)"  后向界定  与向前界定唯一的不同是...向前界定必须是常值,向后界定则是不一定。
#  "+" 1次或多次匹配表示匹配前面的规则至少1次,可以多次匹配,".+?"表示要么出现字符要么就不出现字符
#  结果是part 1 和 part 2
#其实就是把/*和*/去掉,匹配有但不能要

实践代码第7单元


s6 = 'aaa111aaa,bbb222,333ccc,444ddd444,555eee666,fff777ggg'
# "()" 是一个元字符,将 () 之间括起来的表达式定义为“组”(group),
#并且将匹配这个表达式的字符保存到一个临时区域,这个元字符在字符串提取的时候非常有用.
#把一些字符表示为一个整体。改变优先级、定义提取组两个作用。包含在’()’中的内容,
#而虽然前面和后面的内容都匹配成功了,却并不包含在结果中,用group()或group(0)返回匹配的所有结果,
#用 group(1),(2)...返回第1,2...个()里面的内容

#findall里边的()相当于使用group,所以出现的都是括号里边的内容
re.findall( r'([a-z]+)\d+([a-z]+)' , s6 )   
#结果是[('aaa', 'aaa'), ('fff', 'ggg')] 
#只有括号()才呈现这个结果

re.findall( r'(?P<g1>[a-z]+)\d+(?P=g1)' , s6 )
#(?P<name>…)’ 命名组  ,‘(?P=name)’ 调用已匹配的命名组
#这里的正则表达式有函数的变量赋予功能,最重要的是用findall返回的是括号内的内容
#结果是# ['aaa'],只有aaa111aaa前后字符都一样


re.findall( r'([a-z]+)\d+\1' , s6 ) 
# \number  通过序号调用已匹配的组,\1代表返回的组的序号,就是第一个组。
# ()代表着返回满足条件后括号内的数组,如果没有\1,结果是['aaa','bbb','ddd','eee','fff']
# 有\1的数组返回的就是aaa

实践代码第8单元  这里知道了怎么匹配字符串对称的内容

s7 = '111aaa222aaa111 , 333bbb444bb33'
#  数字+字母+数字
re.findall( r'(\d+)([a-z]+)(\d+)' , s7 )
#这里有个默认的边界意识,不可以把222aaa111当成匹配数值,因为前边是字符。
#这个一定要记着,这也是正则表达式需要更准确地原因。
#结果 [('111','aaa','222'),('333','bbb','444')]

re.findall( r'(\d+)([a-z]+)(\d+)(\2)' , s7 )
#其中(\2)表示存入数组的第2个也就是([a-z]+),就是数字+字母+数组+字母。
#()在这里相当于匹配后存入变量,findall是返回这个变量。(\2)是调出存入的第二个变量,也就是出现的两个字母一样
#结果 [('111','aaa','222','aaa')]

re.findall( r'(\d+)([a-z]+)(\d+)(\2)(\1)' , s7 )
#结果 [('111','aaa','222','aaa','111')]



实践代码第9单元 

s8 = '<usr1@mail1>  usr2@maill2'  
#要匹配一些形如 usr@mail 的邮箱地址,有的写成< usr@mail >有的没有,要匹配这两种情况
re.findall( r'(<)?\s*(\w+@\w+)\s*(?(1)>)' , s8 )
# "?" 0或1次匹配 只匹配前面的规则0次或1次
#  \s 匹配间隔符  即匹配空格符、制表符、回车符等表示分隔意义的字符,它等价于[ \t\r\n\f\v]。
# "*" 是指0到多次匹配 "\s*"指的是一个或者多个间隔符
# "\w" 匹配字母和数字 匹配所有的英文字母和数字,即等价于[a-zA-Z0-9]
# "+" 1次或多次匹配  表示匹配前面的规则至少1次,可以多次匹配
# "\w+@\w+" 表示字符@字符
# "(?(1)>)" 表示(1)表示有是否有1这个字符
# 结果是[('<', 'usr1@mail1'), ('', 'usr2@maill2')] 

实例代码第10单元

"""group的用法
正则表达式中,group()用来提出分组截获的字符串,()用来分组
"""
import re
a = "123abc456"
print(re.search("([0-9]*)([a-z]*)([0-9]*)",a).group(0))   #123abc456,同group()就是匹配正则表达式整体结果
print(re.search("([0-9]*)([a-z]*)([0-9]*)",a).group(1))    #123 第一个括号匹配部分
print(re.search("([0-9]*)([a-z]*)([0-9]*)",a).group(2))    #abc 第二个括号匹配部分
print(re.search("([0-9]*)([a-z]*)([0-9]*)",a).group(3))    #456 第三个括号匹配部分
print(re.search("([0-9]*)([a-z]*)([0-9]*)",a).groups())    #('123', 'abc', '456')

li

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值