# 递归常见错误
# 超过最大递归限制
# solve 递归必须要有结束条件
# 返回值
# slove 不要只看到return就认为返回了,要看返回操作是在递归的第几层的时候发生的,然后返回给了谁
# 如果不是返回给最外层函数,调用者就接收不到
# 需要再分析,看如何把结果返回回来
# 循环 ,几乎所有的递归可以用循环解决,快速排序需要用递归实习
# 斐波那契数列,第N个斐波那契数是?
两次递归
from sys import flags
from urllib.request import urlopen
import json
import re
def fib(n):
if n == 1 or n == 2:
return 1
else:
return fib(n-1)+fib(n-2) # 调用了两层,会使效率降低,尽量不用两层
print(fib(10))
一次递归
def fib(n, lis=[0]):
lis[0] += 1
if n == 1 or n == 2:
lis[0] -= 1
return 1, 1
else:
a, b = fib(n-1) # 位置不能放在lis[0] -=1下面
lis[0] -= 1
if lis[0] == 0:
return a+b
return b, a+b
print(fib(50))
阶乘
def fac(n):
if n == 1:
return 1
return n*fac(n-1)
print(fac(10))
常用模块
计算器
re模块
正则表达式 字符串匹配
re模块操作正则表达式
while 1:
phone_number = input('输入手机号码:')
if len(phone_number) == 11\
and phone_number.isdigit()\
and (phone_number.startswith('13')
or phone_number.startswith('14')
or phone_number.startswith('15')
or phone_number.startswith('16')):
print('合法的手机号')
else:
print('手机号不合法,请检查后重新输入')
使用re模块
import re
phone_number = input('输入手机号码:')
if re.match('^(13|14|15|18)[0-9]{9}$', phone_number):
print('合法的手机号')
else:
print('手机号不合法,请检查后重新输入')
正则表达式本身和python没有什么关系,就是匹配字符串内容的一种规则
[字符组]用于同一个位置可能出现的字符的范围,可以用数字、字母、标点
[0-9]表示省略,[a-z],[A-Z],[A-Za-z0-9],A是65,a是97,此正则按照ASCILL码来读取的
元字符 在正则表达式中有特殊的意义
.匹配换行符以外的任意字符
\w 匹配字母或数字或者下划线 word
\s 匹配任意空白符 space
\d 匹配数字 digit
\n 匹配一个换行符
\t 匹配一个制表符
\b 匹配一个单词的结尾 前面要加上结尾的字母
^ 匹配字符串的开始 后面要加上开头的字母、数字、符号
$ 匹配字符串的结尾
\W 匹配非字母或者非数字或者非下划线
\D 匹配非数字
\S 匹配非空白符
a|b 匹配字符a或者字符b 从左向右匹配,匹配到第一个就不匹配第二个
() 匹配括号内的表达式,也表示一个组
[...] 匹配字符组中的字符
[^...] 匹配除了字符组中字符的所有字符 [^ab]除了ab都匹配
[\W\w] 相当于匹配任意字符
元字符可以组合使用
量词
* 重复零次或者更多次 默认多了匹配,贪婪匹配
+ 重复一次或者更多次
?重复零次或者一次
{n} 重复n次
{n,} 重复n次或者更多次
{n,m} 重复n到m次
所有的规则要用在正则匹配的后面,先规则,后跟一个量词,[a-z]+\d+
绿茶白茶黄茶青茶红茶黑茶 用.茶匹配
海燕海娇海东 海.匹配
李杰和李莲英和李二棍子 [^和]+匹配
李杰和李莲英和李二棍子 李.? 前面的,+,?都是贪婪匹配,后面的?使其变成惰性匹配,放在后面会向少的地方匹配
456bdha3 [\d]为4 5 6 3,[\d]+为456 3
分组匹配
#需要对一个整体的事情运用量词时需要用到分组,如([abc][123])+
#身份证号的正则表达式 ,身份证号为15或者18位不能以0开头,15位的为纯数字,18位的可以结尾为x
'^[1-9]\d{14}(\d{2}[0-9x])?$' # 后面的?为量词,匹配0次或者1次,前面的匹配上后面就不匹配了
#2解:
'^([1-9]\d{16}[0-9x]|[1-9]\d{14})$'18位身份证号正则放前面
转义
print(r'\n') # r让字符串不转义
*?重复任意次,但尽可能少重复
+?重复1次或者更多次,但尽可能少重复
??重复0次或者1次,但尽可能少重复
{n,m} ? 重复n到m次,但尽可能少重复
{n,}? 重复n次以上,但尽可能少重复
.*?x 取前面任意长度的字符,直到出现一个x
findall()
search()
match()
ret = re.findall('a', 'eva egon yuan') # 返回所有满足匹配条件的结果,放在列表里,列表
print(ret) # 结果 : ['a', 'a']
# 从前往后,找到一个就返回,返回结果的对象,group()显示结果,找不到返回None,调用group()会报错
ret = re.search('a', 'eva egon yuan').group()
print(ret) # 结果 : 'a'
ret = re.search('a', 'eva egon yuan')
if ret:
print(ret.group())
ret = re.match('a', 'abc').group() # 同search,不过尽在字符串开始处进行匹配
print(ret)
# 结果 : 'a'
# match从头开始匹配,如果这个正则规则从头该市可以匹配上,就返回一个变量,需要group(),没匹配上返回None
split()
sub()
subn()
compile()
finditer()
ret = re.split('[ab]', 'abcd') # 先按'a'分割得到''和'bcd',在对''和'bcd'分别按'b'分割
print(ret) # ['', '', 'cd']
ret = re.sub('\\d', 'H', 'eva3egon4yuan4', 1) # 将数字替换成'H',参数1表示只替换1个
print(ret) # evaHegon4yuan4
ret = re.subn('\\d', 'H', 'eva3egon4yuan4') # 将数字替换成'H',返回元组(替换的结果,替换了多少次)
print(ret)
obj = re.compile('\\d{3}') # 将正则表达式编译成为一个 正则表达式对象,规则要匹配的是3个数字
ret = obj.search('abc123eeee') # 正则表达式对象调用search,参数为待匹配的字符串
print(ret.group()) # 结果 : 123
ret = re.finditer('\\d', 'ds3sy4784a') # finditer返回一个存放匹配结果的迭代器
print(ret) # <callable_iterator object at 0x10195f940>
print(next(ret).group()) # 查看第一个结果
print(next(ret).group()) # 查看第二个结果
print([i.group() for i in ret]) # 查看剩余的左右结果
ret = re.search('^[1-9]\\d{14}(\\d{2}[0-9x])?$', '110105199912122277')
print(ret.group())
print(ret.group(1)) # 227 取到分组里面的,可以用来取局部分组
# 优先级,没有分组机制,使用优先级的形式
ret = re.findall('www.(baidu|oldboy).com', 'www.oldboy.com')
print(ret) # ['oldboy'] 这是因为findall会优先把匹配结果组里内容返回,如果想要匹配结果,取消权限即可
ret = re.findall('www.(?:baidu|oldboy).com', 'www.oldboy.com') # ?:取消分组优先
print(ret) # ['www.oldboy.com']
ret = re.split("\\d+", "eva3egon4yuan")
print(ret) # 结果 : ['eva', 'egon', 'yuan']
ret = re.split("(\\d+)", "eva3egon4yuan")
print(ret) # 结果 : ['eva', '3', 'egon', '4', 'yuan']
# 在匹配部分加上()之后所切出的结果是不同的,
# 没有()的没有保留所匹配的项,但是有()的却能够保留了匹配的项,
# 这个在某些需要保留匹配部分的使用过程是非常重要的。
爬虫的例子,因网站的登录选项,不能实际使用,仅参考
def getPage(url):
response = urlopen(url)
return response.read().decode('utf-8')
def parsePage(s):
com = re.compile(
'<div class="item">.*?<div class="pic">.*?<em .*?>(?P<id>\\d+).*?<span class="title">(?P<title>.*?)</span>'
'.*?<span class="rating_num" .*?>(?P<rating_num>.*?)</span>.*?<span>(?P<comment_num>.*?)评价</span>', re.S)
# 2解
# re.findall('<div class="item">.*?<div class="pic">.*?<em .*?>(?P<id>\\d+).*?<span class="title">(?P<title>.*?)</span>'
# '.*?<span class="rating_num" .*?>(?P<rating_num>.*?)</span>.*?<span>(?P<comment_num>.*?)评价</span>', s, re.S)
# re方法的flags:
# re.I(IGNORECASE)忽略大小写,括号内是完整的写法
# re.M(MULTILINE)多行模式,改变^和$的行为
# re.S(DOTALL)点可以匹配任意字符,包括换行符
# re.L(LOCALE)做本地化识别的匹配,表示特殊字符集 \w, \W, \b, \B, \s, \S 依赖于当前环境,不推荐使用
# re.U(UNICODE) 使用\w \W \s \S \d \D使用取决于unicode定义的字符属性。在python3中默认使用该flag
# re.X(VERBOSE)冗长模式,该模式下pattern字符串可以是多行的,忽略空白字符,并可以添加注释
ret = com.finditer(s)
for i in ret:
yield {
"id": i.group("id"),
"title": i.group("title"),
"rating_num": i.group("rating_num"),
"comment_num": i.group("comment_num"),
}
def main(num):
url = 'https://movie.douban.com/top250?start=%s&filter=' % num
response_html = getPage(url)
ret = parsePage(response_html)
print(ret)
f = open("move_info7", "a", encoding="utf8")
for obj in ret:
print(obj)
data = str(obj)
f.write(data + "\n")
f.close()
count = 0
for i in range(10):
main(count)
count += 25
# url 从网页上把代码搞下来
# bytes类型,decode->为utf-8 网页内容就是待匹配的字符串
# re.findall(正则,待匹配的字符串) # ret是所有匹配到的内容组成的列表
思考
a = '1 - 2 * ( (60-30 +(-40/5) * (9-2*5/3 + 7 /3*99/4*2998 +10 * 568/14 )) - (-4*3)/ (16-3*2) )'
# 去掉所有的空格
# 逻辑 实现加减乘除四则运算和括号优先级
# 先算括号里面的乘除,再算括号里面的加减
# 从括号里面取值要用到正则表达式
ss = '9-2*5/3 + 7 /3*99/4*2998 +10 * 568/14'
# 从一个没有括号的表达式中取乘除法 == 正则表达式