1.正则表达式基本概念
背景
我们要匹配以xxx开头的字符串、xxx结尾的字符串等时,每一次匹配都要单独写一个函数或语句来完成,正则表达式就是将匹配的方法抽象成一个规则,然后使用这个规则来进行文本或数据的匹配。
概念
是使用单个字符串来描述匹配一系列符合某个语法规则的字符串
是对字符串操作的一种逻辑公式
应用场景
处理文本或数据
处理过程
依次拿出表达式和目标数据进行字符比较,如果每一个字符都能匹配,则匹配成功,否则,失败。
2.Python正则表达式之re模块
字符串自带的查找方法
str1.find(str2)
str1.startswith(str2)
str2.endswith(str2)
详见:中的1.4节
re模块使用
导入re模块
import re
生成pattern实例
pa=re.pattern(正则表达式, flag)
参数
正则表达式
最好是raw字符串;
如果正则表达式首位带括号,则最终的match实例.groups()方法可以以元组的形式展示匹配到的字符串,如r'(study)',但是元组中始终只有一个元素。
flag
re.A | re.ASCII
对\w、\W、\b、\B、\d、\D、\s和\S产生影响,编译后的模式对象在进行匹配的时候,只会匹配ASCII字符,而不是Unicode字符。
re.I | re.IGNORECASE
在匹配的时候忽略大小写
re.M | re.MULTILINE
默认,元字符^会匹配字符串的开始处,元字符$会匹配字符串的结束位置和字符串后面紧跟的换行符之前(如果存在这个换行符)。
如果指定了这个选项,则^将会匹配字符串的开头和每一行的开始处,紧跟在每一个换行符后面的位置。
类似的,$会匹配字符串的最后和每一行的最后,在接下来的换行符的前面的位置。
>>> p = re.compile(r'(^hello$)\s(^hello$)\s(^hello$)\s')>>> m = p.search('hello\nhello\nhello\n')>>> print(m)None>>> p = re.compile(r'(^hello$)\s(^hello$)\s(^hello$)\s', re.M)>>> m = p.search('\nhello\nhello\nhello\n')>>> m.groups()('hello', 'hello', 'hello')
re.S | re.DOTALL
使得.元字符可以匹配任何字符,包括换行符。
re.X | re.VERBOSE
这个选项允许编写可读性更强的正则表达式代码,并进行自由的格式化操作。
当这个选项被指定以后,在正则表达式之间的空格符会被忽略,除非这个空格符是在一个字符类中[ ],或者在空格前使用一个反斜杠\。
这个选项允许对正则表达式进行缩进,使得正则表达式的代码更加格式化,更加清晰。并且可以在正则表达式的代码中使用注释,这些注释会被正则表达式引擎在处理的时候忽略。
注释以'#'字符开头。所以如果需要在正则表达式中使用'#'符号,需要在前面添加反斜杠'\#'或者将它放在[]中,[#]。
charref = re.compile(r"""&[#] # Start of a numeric entity reference( 0[0-7]+ # Octal form | [0-9]+ # Decimal form | x[0-9a-fA-F]+ # Hexadecimal form); # Trailing semicolon""", re.VERBOSE)如果没有指定re.**VERBOSE**选项,则相当于: charref = re.compile("&#(0[0-7]+" "|[0-9]+" "|x[0-9a-fA-F]+);")
使用pattern实例来进行匹配
match() 从字符串指定位置开始匹配,匹配到就停止,返回match对象
match(string[, pos[, endpos]]) --> match object or None.
Matches zero or more characters at the beginning of the string
search() 从字符串指定位置之后的任意位置开始匹配,匹配到就停止,返回Match对象
search(string[, pos[, endpos]]) --> match object or None.
Scan through string looking for a match, and return a corresponding match object instance. Return None if no position in the string matches.
findall() 从字符串指定位置之后的任意位置开始匹配,匹配到了继续匹配,返回字符串中所有匹配的字符串组成的列表。
注意:如果正则表达式中有()分组,则findall返回的是被()括起来的分组字符串所组成的列表。
findall(string[, pos[, endpos]]) --> list.
Return a list of all non-overlapping matches of pattern in string.
finditer() 从字符串指定位置之后的任意位置开始匹配,匹配到了继续匹配,返回一个包含了所有的Match对象的迭代器
finditer(string[, pos[, endpos]]) --> iterator.
Return an iterator over all non-overlapping matches for the RE pattern in string. For each match, the iterator returns a match object.
sub() 将字符串通过正则表达式匹配到的字符使用repl进行制定次数的替换(默认全部替换),repl可以是字符串,也可以使方法名。
当为方法名时,repl方法接收匹配到的match对象,且该sub()方法返回repl方法的返回值
sub(repl, string[, count = 0]) --> newstring
Return the string obtained by replacing the leftmost non-overlapping occurrences of pattern in string by the replacement repl.
split() 将字符串通过正则表达式匹配到的字符进行指定次数的分割(默认全部),返回分割后的列表
split(string[, maxsplit = 0]) --> list.
Split string by the occurrences of pattern.
# 导入re模块 >>> import re # 生成pattern对象>>> pa=re.compile(r'(ddd)') # 使用pattern对象通过match方法进行匹配,得到match对象>>> ma=pa.match('dddsssdddsssddd\ndddsssdddsssddd',5)>>> ma.groups()Traceback (most recent call last): File "", line 1, in AttributeError: 'NoneType' object has no attribute 'groups'
# 使用pattern对象通过search方法进行匹配,得到match对象
>>> ma=pa.search('dddsssdddsssddd\ndddsssdddsssddd',5)>>> ma.groups()('ddd',)
# 使用pattern对象通过findall方法进行匹配,得到匹配到的字符串所组成的列表
>>> ma=pa.findall('dddsssdddsssddd\ndddsssdddsssddd',5) >>> ma ['ddd', 'ddd', 'ddd', 'ddd', 'ddd']
# 使用pattern对象通过finditer方法进行匹配,得到匹配到的Match对象所组成的迭代器
>>> for i in pa.finditer('dddsssdddsssddd\ndddsssdddsssddd',5): ... print i ... <_sre.SRE_Match object at 0x0000000002607378> <_sre.SRE_Match object at 0x0000000002544F30> <_sre.SRE_Match object at 0x0000000002607378> <_sre.SRE_Match object at 0x0000000002544F30> <_sre.SRE_Match object at 0x0000000002607378>
# 使用pattern对象通过sub方法进行替换,得到替换后的新字符串
>>> ma=pa.sub('aaa','dddsssdddsssddddddsssdddsssddd') >>> print type(ma),maaaasssaaasssaaaaaasssaaasssaaa >>> ma=pa.sub('aaa','dddsssdddsssddddddsssdddsssddd',2) >>> print type(ma),ma aaasssaaasssddddddsssdddsssddd >>> def upper_str(match): ... return match.group().upper() ... >>> ma=pa.sub(upper_str,'dddsssdddsssddddddsssdddsssddd',2) >>> print type(ma),ma DDDsssDDDsssddddddsssdddsssddd
# 使用pattern对象通过sub方法进行分割,得到分割后的字符串组成的列表
>>> ma=pa.split('dddsssdddsssddddddsssdddsssddd',2) >>> print type(ma),ma['', 'sss', 'sssddddddsssdddsssddd'] >>> ma=pa.split('dddsssdddsssddddddsssdddsssddd') >>> print type(ma),ma ['', 'sss', 'sss', '', 'sss', 'sss', '']
匹配对象属性
group() 返回正则表达式匹配到的字符串
groups() 返回正则表达式匹配到的字符串构成的元组。注意:如果正则表达式中有()分组,则groups()中是被()括起来的分组字符串所组成的列表。
>>> ma = re.match(r'[\w]{6,11}@(163|qq|huawei)(163|qq|huawei)\.com\1\2','yc123456@163qq.com163qq')>>> ma.group()'yc123456@163qq.com163qq'>>> ma.groups()('163', 'qq')
start() 返回匹配的起始位置
end() 返回匹配的结束位置
span() 返回一个包含匹配的起始位置和结束位置的元组(start, end)
string 进行匹配的源字符串
ma.re 进行匹配的正则表达式
3.正则表达式基本语法
匹配单个字符
. 匹配任意字符,除了\n
[...] 匹配字符集。如[a-z]
\d|\D 匹配数字|非数字
\s|\S 匹配空白|非空白
\w|\W 匹配word字符|非word字符。[a-zA-Z0-9]
\[\] 匹配字符串中的[]
匹配多个字符
* 匹配前一个字符0次或无限次
+ 匹配前一个字符1次或无限次。如匹配有效标识符r'[_a-zA-Z]+\w'
? 匹配前一个字符0次或1次。如匹配两位数r'[1-9]?[0-9]'。注:09的匹配结果是0
{m}|{m,n} 匹配前一个字符m次或者m到n次。如匹配qq邮箱r'\w{6,10}@qq.com'
*? |+? |?? *、+、?的匹配模式变为非贪婪模式。即返回的匹配结果会是最少的。
>>> re.findall(r'[0-9]k*','1kkkk')['1kkkk']>>> re.findall(r'[0-9]k*?','1kkkk')['1']>>> re.findall(r'[0-9]k?','1kkkk')['1k']>>> re.findall(r'[0-9]k??','1kkkk')['1']>>> re.findall(r'[0-9]k+','1kkkk')['1kkkk']>>> re.findall(r'[0-9]k+?','1kkkk')['1k']
边界匹配
^ 匹配字符串开头
$ 匹配字符串结尾
\A|\Z 指定的字符串必须为开头|结尾
>>> re.findall(r'\A[0-9].*k\Z','1kkkk')['1kkkk']>>> re.findall(r'\A[0-9].*k\Z','1kkkz')[]
分组匹配
| 匹配左右任意一个表达式。如匹配0~100:r'^[0-9]$|^[1-9][0-9]$|^100$'
>>> re.findall(r'^[0-9]$|^[1-9][0-9]$|^100$','100')['100']>>> re.findall(r'^[0-9]$|^[1-9][0-9]$|^100$','9')['9']>>> re.findall(r'^[0-9]$|^[1-9][0-9]$|^100$','99')['99']>>> re.findall(r'^[0-9]$|^[1-9][0-9]$|^100$','09')
[] 单字符集。
(ab) 括号中的表达式作为一个分组。
从左到右按顺序为1,2,3。常用于不同的个别单词。如匹配163邮箱和qq邮箱:r'\w{6,11}@(163|qq|huawei).com'>>> re.match(r'[\w]{6,11}@(163|qq|huawei)\.com','yc123456@163.com').group()'yc123456@163.com'>>> re.match(r'[\w]{6,11}@(163|qq|huawei)\.com','yc123456@qq.com').group()'yc123456@qq.com'>>> re.match(r'[\w]{6,11}@(163|qq|huawei)\.com','yc123456@huawei.com').group()'yc123456@huawei.com'
\<number> 引用编号为num的分组匹配到的字符串。类似于管道命令中的xargs -i。
注:\1对应第一个()所匹配到的字符串。如果只有1个分组(),但是使用\2,则会报错。如用来匹配XML文件
>>> re.match(r'<(\w+>).* test').group()'test '>>> re.match(r'<(\w+>).* test').group()Traceback (most recent call last): File "", line 1, in AttributeError: 'NoneType' object has no attribute 'group'>>> re.match(r'<(\w+>).* test').group()Traceback (most recent call last): File " ", line 1, in AttributeError: 'NoneType' object has no attribute 'group'
(?P<name>) 给分组起别名
(?P=name) 引用起过别名的分组
>>> re.match(r'[\w]{6,11}@(?P163|qq|huawei)(?P 163|qq|huawei)\.com(?P=type1)(?P=type2)','yc123456@163qq.com163qq').group()'yc123456@163qq.com163qq'>>> re.match(r'[\w]{6,11}@(?P 163|qq|huawei)(?P 163|qq|huawei)\.com(?P=type1)(?P=type2)','yc123456@163qq.com163163').group()Traceback (most recent call last): File " ", line 1, in AttributeError: 'NoneType' object has no attribute 'group'