参考书籍: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