python-day17~18_递归_正则表达式

时间:2022-12-15 17:19:43

1,

#递归函数
#   了解什么是递归 : 在函数中调用自身函数
#   最大递归深度默认是997/998 —— 是python从内存角度出发做得限制


#RecursionError: maximum recursion depth exceeded while calling a Python object
# 递归的错误,超过了递归的最大深度

# import sys
# sys.setrecursionlimit(1000000)
# n = 0
# def story():
#    global n
#    n += 1
#    print(n)
#    story()
# story()

# 如果递归次数太多,就不适合使用递归来解决问题
# 递归的缺点 : 占内存
# 递归的优点: 会让代码变简单

# alex 多大 n = 1 age(1) = age(2)+2 = age(n+1) + 2
# alex比egon大两岁
# egon多大? n = 2 age(2) = age(3) + 2 = age(n+1) +2
# egon比wusir大两岁
# wusir多大 n = 3 age(3) = age(4) + 2 = age(n+1) +2
# wusir比金老板大两岁
# 金老板多大?
# 金老板40了 n = 4 age(4) = 40

# n = 4 age(4) = 40
# n <4 age(n) = age(n+1) +2
def age(n):
  if n == 4:
    return 40
  elif n >0 and n < 4:
    age(n+1) + 2
#
print(age(1))

 

2,递归函数,每个调用结果都用return返回,防止返回不回值

# 二分查找算法 必须处理有序的列表
# l = [2,3,5,10,15,16,18,22,26,30,32,35,41,42,43,55,56,66,67,69,72,76,82,83,88]

def find(l,aim,start = 0,end = None):
  end = len(l) if end is None else end
  mid_index = (end - start)//2 + start
  if start <= end:
    if l[mid_index] < aim:
      return find(l,aim,start =mid_index+1,end=end)
    elif l[mid_index] > aim:
      return find(l, aim, start=start, end=mid_index-1)
    else:
      return mid_index
  else:
    return '找不到这个值'

ret= find(l,44)

print(ret)

一个递归函数中,应避免分拆成2个及以上的递归调用。应该直线式调用

 

3,正则表达式

http://tool.chinaz.com/regex/

re模块

import re

[A-Za-z0-9]字母和数字,可同时放n个字符组

常用元字符
代码 说明
. 匹配除换行符以外的任意字符
\w 匹配字母或数字或下划线word
\s 匹配任意的空白符space
\d 匹配数字digit
\b 匹配单词的开始或结束
^ 匹配字符串的开始
$ 匹配字符串的结束

 

常用限定符
代码/语法 说明
* 重复零次或更多次
+ 重复一次或更多次
? 重复零次或一次
{n} 重复n次
{n,} 重复n次或更多次
{n,m} 重复n到m次

 

常用反义词
代码/语法 说明
\W 匹配任意不是字母,数字,下划线,汉字的字符
\S 匹配任意不是空白符的字符
\D 匹配任意非数字的字符
\B 匹配不是单词开头或结束的位置
[^x] 匹配除了x以外的任意字符
[^aeiou] 匹配除了aeiou这几个字母以外的任意字符

.\b

限定符要放在元字符后面,且只对贴在一起的最近的元字符有效

\w+\d+  #前面的+只对字母有效,后面的+只对数字有效

\d{11}  #匹配有11位长度的数字

\\n 匹配\n

.*?要与其它字符配合写(贪婪匹配),如:

<.*?>  匹配<script><scewe32ript>这2项  # 加上?为将贪婪匹配模式转为非贪婪匹配模式,会匹配尽量短的字符串

.*?x 匹配任意长度字符,直到遇到x字符,就匹配完成

 r'\\n' 匹配r'\n'   # 在字符串之前加r,让整个字符串不转义

?是特别限定符:

 1) 限定符后加?,取最少的动作,即惰性运算;2)用?:取消权限

 

4, 

 # ret = re.findall('[a-z]+', 'eva egon yuan')

# # 返回所有满足匹配条件的结果,放在列表里  
# print(ret)  #输出 ['eva', 'egon', 'yuan']

 

# ret = re.search('a', 'eva egon yuan')
# if ret:
#   print(ret.group())
# 从前往后,找到第一个就返回,返回的变量需要调用group才能拿到结果
# 如果没有找到,那么返回None,调用group会报错

 

# ret = re.match('[a-z]+', 'eva egon yuan')
# if ret:
#    print(ret.group())  #输出:eva
# match是从头开始匹配,如果正则规则从头开始可以匹配上,就返回第一个匹配的变量。
# 匹配的内容需要用group才能显示
# 如果没匹配上,就返回None,调用group会报错

 

# 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',2)
# #将数字替换成'H',返回元组(替换的结果,替换了多少次)
# print(ret)  #输出:('evaHegonH5yuan2', 2)

 

# obj = re.compile('\d{3}')
# #将正则表达式编译成为一个 正则表达式对象,规则要匹配的是3个数字
# ret = obj.search('abc123eeee') #正则表达式对象调用search,参数为待匹配的字符串
# print(ret.group())  #结果 : 123
# ret = obj.search('abcashgjgsdghkash456eeee3wr2') #正则表达式对象调用search,参数为待匹配的字符串
# print(ret.group()) #结果 : 456

# import re
# 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]) #查看剩余的左右结果
# for i in ret:
#    print(i.group())

 

上述函数的flag

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字符串可以是多行的,忽略空白字符,并可以添加注释

如:def findall(pattern, string, flags=0)

 

5,分组 ()与 或 |[^]

import re
# ret = re.search('^[1-9](\d{14})(\d{2}[0-9x])?$','110105199912122277')
# print(ret.group())
# print(ret.group(1))
# print(ret.group(2))

# import re
#
# 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",re.S)
print(ret)   #结果 : ['eva', '3', 'egon', '4', 'yuan']分隔部分一起输出

 

6,匹配标签

import re

ret = re.search("<(?P<tag_name>\w+)>\w+</(?P=tag_name)>","<h1>hello</h1>")
#还可以在分组中利用?<name>的形式给分组起名字
#获取的匹配结果可以直接用group('名字')拿到对应的值
print(ret.group('tag_name'))  #结果 :h1
print(ret.group())  #结果 :<h1>hello</h1>

ret = re.search(r"<(\w+)>\w+</\1>","<h1>hello</h1>")
#如果不给组起名字,也可以用\序号来找到对应的组,表示要找的内容和前面的组内容一致
#获取的匹配结果可以直接用group(序号)拿到对应的值
print(ret.group(1))
print(ret.group())  #结果 :<h1>hello</h1>

  

7,

三级菜单

python-day17~18_递归_正则表达式python-day17~18_递归_正则表达式
menu = {
    '北京': {
        '海淀': {
            '五道口': {
                'soho': {},
                '网易': {},
                'google': {}
            },
            '中关村': {
                '爱奇艺': {},
                '汽车之家': {},
                'youku': {},
            },
            '上地': {
                '百度': {},
            },
        },
        '昌平': {
            '沙河': {
                '老男孩': {},
                '北航': {},
            },
            '天通苑': {},
            '回龙观': {},
        },
        '朝阳': {},
        '东城': {},
    },
    '上海': {
        '闵行': {
            "人民广场": {
                '炸鸡店': {}
            }
        },
        '闸北': {
            '火车战': {
                '携程': {}
            }
        },
        '浦东': {},
    },
    '山东': {},
}

menu
menu
python-day17~18_递归_正则表达式python-day17~18_递归_正则表达式
def threeLM(dic):
    while True:
        for k in dic:print(k)
        key = input('input>>').strip()
        if key == 'b' or key == 'q':return key
        elif key in dic.keys() and dic[key]:
            ret = threeLM(dic[key])
            if ret == 'q': return 'q'

threeLM(menu)

递归函数实现三级菜单
递归函数实现三级菜单

 

 

 

学习:
https://www.cnblogs.com/Eva-j/articles/7228075.html#_label10

 

a = '1 - 2 * ( ( 6 0 -3 0  +(-40/5) * (9-2*5/3 + 7 /3*99/4*2998 +10 * 568/14 )) - (-4*3)/ (16-3*2) )'
python-day17~18_递归_正则表达式python-day17~18_递归_正则表达式
import re
def compu(lin):
    '''计算字符串中的数字'''
    ret2 = re.findall('(?:-?\d+\.\d+)|(?:-?\d+)', lin)  # 拿到所有数字
    # print(ret2, len(ret2))
    com_alpha = re.findall('[(\+)|\-|(\*)|/]', lin[1:])  # 拿到所有运算符
    # print(com_alpha, len(com_alpha))
    count = 0
    com_alpha_new = []
    ret2_new = []
    flag_multiply = False
    temp = 0
    if '*' in com_alpha or '/' in com_alpha:
        while count < len(com_alpha):  # 乘除运算后的数字,放到新列表中
            if com_alpha[count] == '*':
                if flag_multiply == False:
                    temp = float(ret2[count]) * float(ret2[count + 1])
                    flag_multiply = True
                else:
                    temp = temp * float(ret2[count + 1])
            elif com_alpha[count] == '/':
                if flag_multiply == False:
                    temp = float(ret2[count]) / float(ret2[count + 1])
                    flag_multiply = True
                else:
                    temp = temp / float(ret2[count + 1])
            else:
                if flag_multiply:
                    ret2_new.append(temp)  # temp数字(乘除运算完成)放到新列表中
                    com_alpha_new.append(com_alpha[count])
                    flag_multiply = False
                else:
                    ret2_new.append(ret2[count])
                    com_alpha_new.append(com_alpha[count])  # +-运算符没有运算,原样放到新列表中
            count += 1
        if flag_multiply:
            ret2_new.append(temp)  # 循环后最后一个temp数字(乘除运算完成)放到新列表中
            flag_multiply = False
        ret2 = ret2_new
        com_alpha = com_alpha_new
        # print(ret2, com_alpha)
    if len(ret2) > 1:
        sum_result = 0.0
        flag_add = False
        for i in ret2:  # 开始加法运算,不用关心列表中的运算符是否是减号
            sum_result += float(i)
        ret2 = sum_result
    return ret2[0] if type(ret2) is list else ret2  # 返回的是float类型值

def partition_right(a):
    '''对运算符进行)圆括号分拆
        由partition()函数调用'''
    ret = re.split('\)', a,1)  # 否则,对第一个)进行分拆,生成list值
    # ret2 = re.split('\)', a,1)
    print(ret,'---partition_right')
    ret[0] = str(compu(ret[0]))
    ret = ')'.join(ret)
    print(ret,'---partition_right')
    return ret  # 第1个)左边的数计算后的,以及没有计算的字符串,连接后返回

def partition(a):
    '''对运算符进行圆括号分拆
        需调用partition_right(a)函数'''
    if '(' not in a:  # 如没有(,进行第1个)左边的字符串计算
        ret = partition_right(a)
    else:  # 否则,是含()的完整运算符
        ret = re.split('\(', a)  # 对所有)进行分拆,生成list值
        ret2 = re.split('\(', a)
        print(ret,'---partition')
    count = 0
    for i in ret:
        if ')' in i:  # 说明是(分拆部分,进行运算
            ret_new = re.split('\).*?', i, 1)  # 找到小括号的最里层
            # print(ret_new)
            temp = compu(ret_new[0])
            ret_new[0] = str(temp)    # 运算结果不管正负,去掉一个)括弧
            ret_new = ''.join(ret_new)
            ret[count] = ret_new
            # print(ret_new, '-' * 10)
        count += 1
    print(ret, '#' * 10)
    count = len(ret) - 1
    ret_new = ''
    while count >= 0:  # 从最右边开始合并运算字符串
        if ret_new == '':
            ret_new = ret[count]
        elif ret[count] == '':
            # single_digit = len(re.findall('(?:-?\d+\.\d+)|(?:-?\d+)', ret[count + 1]))
            if (ret[count-1][-1] in '+-*/') and (ret[count+1] != ret2[count+1]):  # 看后面数字有没有运算过
                ret_new = '(' + ret_new  # 运算过就去掉一个(
            else:
                ret_new = ret[count] + '((' + ret_new
        elif ret_new[0] != '-':  # 判断后面的数如是正数,直接跟前面连接
            ret_new = ret[count] + ret_new
        else:  # 后面的数如是负数
            single_digit = len(re.findall('(?:-?\d+\.\d+)|(?:-?\d+)', ret[count+1]))
            if ret[count][-1] in '+-*/' and single_digit != 1:  # 如前面是运算符,后面不是单一数字
                temp = re.split('\)', ret_new, 1)
                ret_new = '))'.join(temp)
                ret_new = ret[count] + '(' + ret_new  # 补上()
            elif ret[count][-1] == '+':  # 如后面是单一数字
                temp = re.split('\)', ret_new, 1)
                ret_new = ')'.join(temp)
                ret_new = ret[count][:-1] + ret_new  # 负负得正后连接
            elif ret[count][-1] == '-':  # 如后面是单一数字
                temp = re.split('\)', ret_new, 1)
                ret_new = ')'.join(temp)
                ret_new = ret[count][:-1] + '+' + ret_new[1:]  # 负负得正后连接
            elif ret[count][-1] in '/*':  # 如后面是单一数字,前面是乘除运算
                single_digit = len(re.findall('(?:-?\d+\.\d+)|(?:-?\d+)', ret[count]))  # 前面是否是单一数字
                if single_digit > 1:  # 前面是多个数字的运算
                    count2 = len(ret[count])
                    flag = False
                    while flag == False:
                        count2 -= 1  # 当flag为True时,count2就是+或-的索引号
                        if ret[count][count2] in '+-':
                            flag = True
                    if ret[count][count2] == '+':
                        temp = ret[count][:count2]
                        temp = temp + '-' + ret[count][count2 + 1:]
                        ret[count] = temp
                    else:
                        temp = ret[count][:count2]
                        temp = temp + '+' + ret[count][count2 + 1:]
                        ret[count] = temp
                else:  # 单一数字
                    if ret[count][0] == '-':
                        ret[count][0] = ret[count][1:]
                    else:
                        ret[count] = '-' + ret[count]
                ret_new = ret[count] + ret_new[1:]
        count -= 1
    ret = ret_new
    print(ret)   # 新的完整运算字符串
    if '(' not in ret:
        temp = re.search('[(\+)|\-|(\*)|/]',ret)
        if temp:
            return compu(ret)
    else:  # 运算过最内层()后,运算上一层的()
        return partition(ret)

a = '1 - 2 * ( ( 6 0 -3 0  +(-40/5) * (9-2*5/3 + 7 /3*99/4*2998 +10 * 568/14 )) - (-4*3)/ (16-3*2) )'
a = a.replace(' ','')
print(a)
print(partition(a))
作业答案

耗费了元旦假3天。。。