正则表达式
正则表达式是对字符串操作的一种逻辑公式,就是用事先定义好的一些特定字符、及这些特定字符的组合,组成一个“规则字符串”,这个“规则字符串”用来表达对字符串的一种过滤逻辑,也可以从字符串中获取我们想要的特定部分。正则表达式是一种文本模式,模式描述在搜索文本时要匹配的一个或多个字符串。
字符描述
\ 将下一个字符标记为一个特殊字符、或一个原义字符、或一个向后引用、或一个八进制转义符。
^ 匹配输入字符串的开始位置。
$ 匹配输入字符串的结束位置。
* 匹配前面的子表达式零次或多次。
+ 匹配前面的子表达式一次或多次。
? 匹配前面的子表达式零次或一次。
{n} n是一个非负整数,匹配确定的n次。
{n,} n是一个非负整数。至少匹配n次。
{n,m} m和n均为非负整数,其中n<=m。最少匹配n次且最多匹配m次。
? 当该字符紧跟在任何一个其他限制符(*,+,?,{n},{n,},{n,m})后面时,匹配模式是非贪婪的。非贪婪模式尽可能少的匹配所搜索的字符串,而默认的贪婪模式则尽可能多的匹配所搜索的字符串。
. 匹配除“\n”之外的任何单个字符。要匹配包括“\n”在内的任何字符,请使用像“(.|\n)”的模式。
(pattern) 匹配pattern并获取这一匹配。
(?:pattern) 匹配pattern但不获取匹配结果,也就是说这是一个非获取匹配,不进行存储供以后使用。
(?=pattern) 正向肯定预查,在任何匹配pattern的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。
(?!pattern) 正向否定预查,在任何不匹配pattern的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。
(?<=pattern) 反向肯定预查,与正向肯定预查类拟,只是方向相反。
(?<!pattern) 反向否定预查,与正向否定预查类拟,只是方向相反。
x|y 匹配x或y。
[xyz] 字符集合,匹配所包含的任意一个字符。
[^xyz] 负值字符集合,匹配未包含的任意字符。
[a-z] 字符范围,匹配指定范围内的任意字符。
[^a-z] 负值字符范围,匹配任何不在指定范围内的任意字符。
\b 匹配一个单词边界,也就是指单词和空格间的位置。
\B 匹配非单词边界。“er\B”能匹配“verb”中的“er”,但不能匹配“never”的“er”。
\cx 匹配由x指明的控制字符。。
\d 匹配一个数字字符。等价于[0-9]。
\D 匹配一个非数字字符。等价于[^0-9]。
\f 匹配一个换页符。等价于\x0c和\cL。
\n 匹配一个换行符。等价于\x0a和\cJ。
\r 匹配一个回车符。等价于\x0d和\cM。
\s 匹配任何空白字符,包括空格、制表符、换页符等等。等价于[ \f\n\r\t\v]。
\S 匹配任何非空白字符。等价于[^ \f\n\r\t\v]。
\t 匹配一个制表符。等价于\x09和\cI。
\v 匹配一个垂直制表符。等价于\x0b和\cK。
\w 匹配包括下划线的任何单词字符。等价于“[A-Za-z0-9_]”。
\W 匹配任何非单词字符。等价于“[^A-Za-z0-9_]”。
\xn 匹配n,其中n为十六进制转义值。十六进制转义值必须为确定的两个数字长。
\num 匹配num,其中num是一个正整数。对所获取的匹配的引用。
\n 标识一个八进制转义值或一个向后引用。如果\n之前至少n个获取的子表达式,则n为向后引用。否则,如果n为八进制数字(0-7),则n为一个八进制转义值。
\nm 标识一个八进制转义值或一个向后引用。如果\nm之前至少有nm个获得子表达式,则nm为向后引用。如果\nm之前至少有n个获取,则n为一个后跟文字m的向后引用。如果前面的条件都不满足,若n和m均为八进制数字(0-7),则\nm将匹配八进制转义值nm。
\nml 如果n为八进制数字(0-3),且m和l均为八进制数字(0-7),则匹配八进制转义值nml。
\un 匹配n,其中n是一个用四个十六进制数字表示的Unicode字符。
习题1
def main():
username = 'jakdvia####'
'''
注意match()与search()之间的区别:
match()函数只检测RE是不是在string的开始位置匹配,
search()会扫描整个string查找匹配;
也就是说match()只有在0位置匹配成功的话才有返回,
如果不是开始位置匹配成功的话,match()就返回none。
'''
if re.match(r'\w{6,20}', username):
print('匹配成功!')
else:
print('匹配失败!')
m = re.match(r'\w{6,20}', username)
print(m)
print(m.span())
# 返回一个元组包含匹配 (开始,结束) 的位置
print(m.group())
# 返回被re匹配的字符串
if __name__ == '__main__':
main()
习题2
import re
def is_qq_password():
qq = input('QQ: ')
password = input('Password: ')
# compile() 函数将一个字符串编译为字节代码
m1 = re.match(r'^[1,9]\d{4,11}$', qq)
# match是从头开始匹配的, search从任何位置开始匹配
if not m1:
print('输入QQ无效!')
pattern1 = re.compile(r'^\w[0-9a-zA-Z_]{6,20}')
m2 = pattern1.match(password)
# m2 = re.match(r'^\w[0-9a-zA-Z_]{6,20}$', password)
if not m2:
print('输效密码无效!')
if m1 and m2:
print('输入信息匹配!')
if __name__ == '__main__':
is_qq_password()
习题3
import re
def main():
pattern = re.compile(r'(?<=\D)1[345789]\d{9}(?=\D)')
sentence = '重要的事情说8130000000000遍我的手机号是13512346789不是13300998765,舒玲的手机号是13548068412,不是110'
mylist = re.findall(pattern, sentence)
print(mylist)
print(pattern.finditer(sentence))
# iter - iterator - 迭代器
for temp in pattern.finditer(sentence):
print(temp)
print(temp.group())
# group()用来提出分组截获的字符串
print(temp.span())
# 返回一个元组包含匹配 (开始,结束) 的位置
if __name__ == '__main__':
main()
习题4
from re import findall, sub
def foo(modv):
val = int(modv.group('foo1'))
return str(val ** 2)
def main():
content = 'abc124hello46goodbye67shit'
list1 = findall(r'\d+', content)
print(list1)
mylist = list(map(int, list1))
print(mylist)
print(sum(mylist) / len(mylist))
print(sub(r'(?P<foo1>\d+)(?P<foo2>[hg])', foo, content))
print()
print(sub(r'(?P<foo1>\d+)', foo, content))
# ?P<name>是给正则中的组起一个名字
if __name__ == '__main__':
main()