特殊符号和字符(元字符)
表示法 | 描述 | 正则表达式示例 |
---|---|---|
符号 | ||
literal | 匹配文本字符串的字面值 | foo |
re1|re2 | 匹配正则表达式re1或者re2 | foo|bar |
. | 匹配任何字符(除\n之外) | b.b |
^ | 匹配字符串起始部分 | |
$ | 匹配字符串终止部分 | |
* | 匹配0次或多次前面出现的正则表达式 | |
+ | 匹配1次或多次前面出现的正则表达式 | |
? | 匹配0次或1次前面出现的正则表达式 | |
{N} | 匹配N次前面出现的正则表达式 | |
{M,N} | 匹配M-N次前面出现的正则表达式 | |
[…] | 匹配来自字符集的任意单一字符 | |
[…x-y…] | 匹配x~y范围中的任意单一字符 | |
[^…] | 不匹配来自字符集的任何一个字符,或某一范围的字符 | |
(*|+|?|{})? | 用于匹配上面频繁出现/重复出现符号的非贪婪版本(*,+,?,{}) | |
(…) | 匹配封闭的正则表达式,然后另存为子组 | |
特殊字符 | ||
\d | 匹配任何十进制数字,与[0-9]一致(\D与\d相反,匹配任何非十进制数,与[^0-9]一样) | |
\w | 匹配任何字母数字字符(\W与之相反) | |
\s | 匹配任何空格字符,与[\n\t\r\v\f]一致,(\S与之相反) | |
\b | 匹配任何单词边界(\B与之相反) | |
\N | 匹配已保存的数组N | |
\c | 逐字匹配任何特殊字符c(即按字面匹配,不转义了) | |
\A(\Z) | 匹配字符串的起始(结束)(与^和$一致) | |
拓展表示法 | ||
(?iLmsux) | 在正则表达式中嵌入一个或多个特殊“标记”参数(就是下面re中那个模块属性)(或者通过函数/方法) | |
(?:…) | 表示一个匹配不用保存的分组 | |
(?P<name>…) | ||
(?P=name) | ||
(?#…) | 表示注释 | |
(?=…) | 正向前视断言 | |
(?!..) | 负向前视断言 | |
(?<=…) | 正向后视断言 | |
(?<!..) | 负向前视断言 | |
(?(id/name)Y|N) | 如果某匹配组存在,就与Y匹配,否则与x匹配 |
使用圆括号()指定分组
()作用:
①对正则表达式进行分组
②匹配子组
分组好处:
当有两个不同的正则表达式而且想用他们来比较同一字符串
分组可以对整个分组使用重复操作符。
副作用:
匹配模式的子字符串可以保存起来供后续使用
拓展符号:
1.(?iLmsux)在正则表达式中指定特殊标记
①标记——re.I/re.IHNORECESE
>>> import re
>>> re.findall('(?i)yes','yes?Yes! YES!!!')#相当于使用了re.I
['yes', 'Yes', 'YES']
②标记——re.M/re.MULTILINE,可匹配多行
>>> re.findall('(?im)(^th[\w ]+)',"""
This line is the first,
another line,
that line,it's the best
""")
['This line is the first', 'that line']
③标记——re.S/re.DOTALL,点号(.)能匹配任何字符,包括\n
④标记——re.X/re.VERBOSE,允许用户通过抑制在正则表达式中使用空白符(除了在字符类或者反斜线转义中)来创建更易读的正则表达式,此外,散列,注释和井号也可用于一个注释的开始,只要他们不在一个用反斜线转义的字符类中
>>> re.search(r'''(?x)
\((\d{3})\) #区号
[ ] #空白符
(\d{3}) #前缀
- #横线
(\d{4}) #终点数字
''','(800) 555-1212').groups()
('800', '555', '1212')
2.(?:…)
对部分正则表达式进行分组,但是不会保存该分组.
3.(?P<name>) , (?P=name)
(?P<name>) 使用一个名称标识符(而不是默认的1,2,3,…,N)来保存匹配分组,
使用默认数字来标识分组时,通过\1 , \2 , \3,…\N来检索。
而使用名称标识符时,用(\g<name>)来检索。
>>> re.sub(r'\((?P<areacode>\d{3})\) (?P<prefix>\d{3})-(?:\d{4})','(\g<areacode>) \g<prefix>-xxxx','(800) 555-1212')
'(800) 555-xxxx'
!!!
(?P=name)直接使用前者(?P<name>) 的模式而不用重新写相同的正则表达式
>>> bool(re.match(r'''(?x)
#match(800) 555-1212 ,save areacode,prefix,no.
\((?P<areacode>\d{3})\)[ ](?P<prefix>\d{3})-(?P<number>\d{4})
#space
[ ]
#match 800-555-1212
(?P=areacode)-(?P=prefix)-(?P=number)
#space
[ ]
#match 18005551212
1(?P=areacode)(?P=prefix)(?P=number)
''','(800) 555-1212 800-555-1212 18005551212'))
True
4.(?=…), (?!…)
5.(?(id/name)Y|X)
二,正则表达式与Python
1.re模块
函数/方法 | 描述 |
---|---|
仅是re模块函数 | |
compile(pattern,flags=0) | |
re模块函数和正则表达式对象的方法 | |
match(pattern,string,flags=0) | |
search(pattern,string,flags=0) | |
findall(pattern,string[,flags]) | 查询字符串中的某个正则表达式模式全部的非重复出现情况。返回一个列表。 |
finditer(pattern,string[,flags]) | 返回迭代器,对于每一次匹配迭代器都返回一个匹配对象 |
splitl(pattern,string,max=0) | |
re模块函数和正则表达式对象方法 | |
sub(pattern,repl,string,count=0) | |
purge() | |
常用的匹配对象方法 | |
group(num=0) | |
groups(default=None) | |
groupdict(default=None) | |
常用的模块属性 | |
re.I,re.IGNORECASE | 不区分大小写的匹配 |
re.L,re.LOCALE | 根据所使用的本地语言环境通过\w,\W,\b,\B,\s,\S实现匹配 |
re.M,re.MULTILINE | ^和$分别匹配目标字符串中行的起始和结尾,而不是严格匹配整个字符串本身的起始和结尾。 |
re.S,re.DOTALL | “.”(点号)可以匹配包括\n在内的全部字符 |
re.X,re.VERBOSE | 通过反斜线转义,否则所有空格加上#(以及在该行中所有的后续文字)都被忽略,除非在一个字符类中或者允许注释并提高可读性 |
2.
编译正则表达式:
在模式匹配发生前,正则表达式模式必须编译成正则表达式对象。
由于其被多次使用,强烈建议使用预编译
①complie函数
一些特殊的正则表达式编译,可选的标记可能以参数的形式给出,这些标记允许不区分大小写的匹配,使用系统的本地化设置来匹配字母数字等,它们可以通过安慰或操作符(|)合并。
若想在方法中使用这些标记,它们必须已经集成到已编译的正则表达式对象中,或使用直接嵌入到正则表达式本身的(?F)标记,其中F是一个或多个i,m,s,同时使用时(?im)不要用|,其实就是拓展符号中的(?iLmsux)
②匹配对象以及group()和groups()方法
成功调用match()或search()后返回匹配对象。匹配对象的两种方法group() , groups()
group()返回整个匹配对象或特定子组
group(num=0)
groups()仅返回一个包含全部匹配子组的元组。
groups(default=None)
③使用match()方法匹配字符串
试图从字符串的起始部分对模式进行匹配。
匹配成功,返回匹配对象
匹配失败,返回None
>>> import re
>>> m=re.match('foo','food on the table')
>>> if m is not None:
m.group()#不用if,若匹配失败,会出现AttributeError异常
'foo'
>>> m
<re.Match object; span=(0, 3), match='foo'>
④使用search()在一个字符串中查找模式
使用match
>>> m=re.match('foo','seafood')
>>> if m is not None:m.group()
>>> #匹配失败
使用search:
>>> re.search('foo','seafood').group()
'foo'
!!!match与search都可使用可选的标记参数。
等价的正则表达式方法还可以使用可选的pos和endpos参数赖志定目标字符串的搜索范围。
3.分组与其他符号
分组
>>> m=re.match('(a)(b)','ab')
>>> m.group()
'ab'
>>> m.group(1)
'a'
>>> m.group(2)
'b'
>>> m.groups()
('a', 'b')
>>> m=re.match('(a(b))','ab')
>>> m.group()
'ab'
>>> m.group(1)
'ab'
>>> m.group(2)
'b'
>>> m.groups()
('ab', 'b')
还可使用\N(N为分组编号)使用分组
>>> re.sub(r'(\d{1,2})/(\d{1,2})/(\d{2}|d{4})',r'\2/\1/\3','2/20/991')
'20/2/991'
边界
>>> m=re.search(r'\bthe','bite the dog')
>>> if m is not None:
m.group()
'the'
>>> m=re.search(r'\bthe','bitethe dog')
>>> if m is not None:
m.group()
#查找(匹配)失败
>>> m=re.search(r'\Bthe','bitethe dog')
>>> if m is not None:
m.group()
'the'
4.findall与finditer方法
使用findall()和finditer()查找每一次出现的位置
findall()查询字符串中的某个正则表达式模式全部的非重复出现情况。返回一个列表。
(如果没找到,则返回空列表)
>>> re.findall('car','carry the barcardi to the car')
['car', 'car', 'car']
>>> re.findall(r'(car).{2,7}(the)','carry the barcardi to the car')
[('car', 'the'), ('car', 'the')]
finditer(),返回迭代器,对于每一次匹配迭代器都返回一个匹配对象。
注意Python3中迭代器用方法__next__()
>>> re.finditer(r'(th\w+) and (th\w+)','This and that',re.I).__next__().group()
'This and that'
!!!match与search都可使用可选的标记参数。
等价的正则表达式方法还可以使用可选的pos和endpos参数赖志定目标字符串的搜索范围。
5.sub()和subn()搜索与替换
将字符串中所有匹配正则表达式的部分进行某种形式的替换。
返回替换后的字符串
subn比之sub多返回一个替换数目,以元组形式——(字符串,n)
>>> re.sub('[ae]','x','abcdef')
'xbcdxf'
>>> re.subn('[ae]','x','abcdef')
('xbcdxf', 2)
还可使用\N(N为分组编号)使用分组
>>> re.sub(r'(\d{1,2})/(\d{1,2})/(\d{2}|d{4})',r'\2/\1/\3','2/20/991')
'20/2/991'
6.在限定模式上使用split()分割字符串
>>> import re
>>> DATA =(
'Mountain View, CA 94040',
'Sunnyvale, CA',
'Los Altos, 94026',
'Cupertino 95014',
'Palo Alto CA',
)
>>> for datum in DATA:
print(re.split(', |(?= (?:\d{5}|[A-Z]{2}))',datum))
['Mountain View', 'CA', ' 94040']
['Sunnyvale', 'CA']
['Los Altos', '94026']
['Cupertino', ' 95014']
['Palo Alto', ' CA']
7.杂项
\w 和 \W 同时受 re.L/re.LOCALE 和 Unicode(re.U/re.UNICODE) 影响
!!!尽量使用 Python原始字符串
因为ASCLL和正则表达式特殊字符之间存在冲突。
比如\b在ASCLL码中标识退格 ,正则表达式中表示单词边界,
需要“\b”
建议使用原始字符串r“…”