# Python 7.模式匹配与正则表达式
# 正则表达式的模块 re(Regex)
# 方法:
# 1.用import re 导入正则表达式模块。
# 2.用re.compile()函数创建一个Regex对象。
# 3.想Regex对象的search()方法传入想查找的字符串,它返回一个Match对象。
# 4.调用Match对象的group()方法,返回实际匹配文本的字符串。
#*貌似需要对Match对象进行空值判断。
import re
# 查找电话号码 格式:111-111-1111
phoneNum = re.compile(r'\d\d\d-\d\d\d-\d\d\d\d')
mo = phoneNum.search('my number is 230-321-3445')
if mo != None:
print('number :' + mo.group())
else:
print('number :' + 'None')
phoneNum = re.compile(r'\d{3}-\d{3}-\d{4}')
mo = phoneNum.search('my number is 300-321-3445')
if mo != None:
print('number :' + mo.group())
else:
print('number :' + 'None')
# 用括号分组
# 创建分组:(\d\d\d)-(\d\d\d-\d\d\d\d) 分两组
phoneNum = re.compile(r'(\d\d\d)-(\d\d\d-\d\d\d\d)')
mo = phoneNum.search('my number is 230-321-3445')
print(mo.group(1))
# mo.group()传入0 或者 传入参入,则全部打印
#如果想要一次性获取全部分组,使用groups()方法。
print(mo.groups())
# 用管道匹配多个分组 字符 | 称为 “管道”
name = re.compile(r"kyle|John")
mo = name.search('mane is John')
print(mo.group())
# 以ky开头的字符串匹配
name = re.compile(r"ky(le|hn|la)")
mo = name.search('mane is kyla')
print(mo.group())
# 用问号实现可选匹配 (s)? 表示s可选可不选
name = re.compile(r"kyl(e)?r")
mo = name.search('mane is kyler')
print(mo.group())
# 用星号匹配零次 或 多次 *
name = re.compile(r"kyl(e)*r")
mo = name.search('mane is kyleeer')
print(mo.group())
# 如果需要匹配*号, 则需要在星号前加\*
name = re.compile(r"kyl(e\*)*r")
mo = name.search('mane is kyle*r')
print(mo.group())
# 用加号匹配一次或多次 + (至少有一次)
name = re.compile(r"kyl(e)+r")
mo = name.search('mane is kyleeer')
print(mo.group())
# 用花括号匹配特定次数
phoneNum = re.compile(r'\d{3}-\d{3}-\d{4}')
mo = phoneNum.search('my number is 300-321-3445')
print('number :' + mo.group())
# (ha){3,5} == 'hahaha'|hahahaha|hahahahaha
# 贪心 和 非贪心匹配
# 贪心返回最长字符串
# 非贪心返回最短字符串
name = re.compile(r"(ky){2,5}")
mo = name.search('mane is kykykykyky')
print(mo.group())
name = re.compile(r"(ky){2,5}?")
mo = name.search('mane is kykykykyky')
print(mo.group())
# findall()方法 返回全部匹配的文本
phoneNum = re.compile(r'\d\d\d-\d\d\d-\d\d\d\d')
mo = phoneNum.findall('my number is 230-321-3445, 324-234-2234')
print(mo)
# 字符分类
# \d 0到9的任意数字
# \D 除0到9的数字意外的任何字符
# \w 任何字母、数字或下划线字符(可以认为是匹配“单词”字符)
# \W 除字母、数字、和下划线以外的任何字符
# \s 空格、制表符或换行符(可以认为是匹配“空白”字符)
# \S 除空格、制表符和换行符以外的任何字符
xmasRegex = re.compile(r"\d+\s\w+")
mo = xmasRegex.findall('12 twl, 11 ele, 10 ten, 9 nine, 8 eight, 7 seven, 6 six,'
'5 five, 4 four, 3 three, 2 two, 1 one, 0 zero')
print(mo)
# 建立自己的字符分类[]
# 字符分类[aeiouAEIOU]将所有元音字符 输出
vowel = re.compile(r'[aeiouAEIOU]')
mo = vowel.findall('we are family')
print(mo)
# 除去元音字符的其他字符 在前面加^
vowel = re.compile(r'[^aeiouAEIOU]')
mo = vowel.findall('we are family')
print(mo)
# 插入字符和美元字符^ $
# ^ 字符表示匹配必须发生在被查找文本的开始处
# $ 字符表示匹配必须发生在被查找文本的结尾处
begins = re.compile(r'^hello')
mo = begins.search('hello world')
print(mo.group())
print(mo)
ends = re.compile(r'\d$')
mo = ends.findall('I an 25,26')
print(mo)
whole= re.compile(r'^\d+$')
mo = whole.findall('126234')
print(mo)
# 通配符 "."
begins = re.compile(r'.at')
mo = begins.findall('what hat cat in flat')
print(mo)
# 用点—星匹配所有字符串
begins = re.compile(r'<.*?>')
mo = begins.findall('<what> hat <cat in flat>')
print(mo)
# 用句点字符匹配换行 re.DOTALL
# 返回遇见第一个换行前的字符串
xmasRegex = re.compile('.*')
mo = xmasRegex.search('12 twl, 11 ele, 10 ten, 9 nine, \n8 eight, 7 seven, 6 six,'
'5 five, \n4 four, 3 three, 2 two, 1 one, 0 zero')
print(mo.group())
# 所有字符串
xmasRegex = re.compile('.*', re.DOTALL)
mo = xmasRegex.search('12 twl, 11 ele, 10 ten, 9 nine, \n8 eight, 7 seven, 6 six,'
'5 five, \n4 four, 3 three, 2 two, 1 one, 0 zero')
print(mo.group())
# 正则表达式符号复习
# 1: ?匹配零次或者一次前面的分组
# 2:*匹配零次或者多次前面的分组
# 3:+匹配一次或者多次前面的分组
# 4:{n}匹配n次前面的分组
# 5:{n,}匹配n次或者更多前面的分组
# 6:{,m}匹配零次到m次前面的分组
# 7:{n,m}匹配至少n次,至多m次前面的分组
# 8:{n,m}?或*?或+?对前面的分子进行非贪心分配
# 9:^spam意味着字符串必须以spam开始
#10:spam$意味着字符串必须以spam结束
#11:.匹配所有字符,换行符除外
#12:\d,\w,\s 分别匹配数字,单词和空格
#13:\D,\W,\S 分别匹配除数字,单词和空格外的所有字符
#14:[abc]匹配方括号内的任意字符 诸如 a, b, c
#15:[^abc]匹配不在括号内的任意字符串
# 不区分大小写的匹配 re.UGBIGECASE 或 re,I
begins = re.compile(r'my', re.I)
mo = begins.findall('My name is Kyle')
print(mo)
# 用sub() 方法替换字符串
name = re.compile(r"John")
mo = name.sub('Kyle', "John is a boy")
print(mo)
# 管理复杂的正则表达式 re.VERBOSE 作为第二个参数,略过其中的注释和空白符