Python复习 Day4 字符串和常见数据结构

一、字符串

1.1 表示

字符串是0个或多个字符的集合,可记为:s=a1a2a3...an,一般用单引号或者双引号包围起来。

s1 = '今天'
s2 = "开始"
#三引号包围的字符串可以换行
s3 = """
    我要
    自己上厕所
    """
print(s1,s2,s3)

1.2 编码

字符串主要有两种类型:str和byte

strUnicode字符在内存中,常以Unicode字符表示
byte二进制数据(包括编码的文本)在磁盘上或在网络传输时,需要把str转换为byte,就需要编码

常见字符串编码标准:

ASCII最早的字符串编码
UTF-8国际通用英文1字符,中文3字符
GBK,GB2312中文编码标准英文1字符,中文2字符

编码:字符串转化为字节(byte)

# 使用str.encode([encoding='utf-8'],[errors='strict'])编码
str1 = '12345'
# 编码默认为utf-8
print(str1.encode('utf-8'))
print(str1.encode()) # 结果一样

 解码:字节转化为字符串

# 使用byte.decode([encoding='utf-8'][,errors='strict'])解码
str1 = '12345'
# 编码
byte = str1.encode('utf-8')
# 解码
print(byte.decode('utf-8')) #'12345'

1.3 转义

字符串中,可以用反斜杠“\”对字符进行转义

转义后的字符含义
\n换行
\t制表(横向跳格)
\'字符'
\"字符"
\\字符\

还可以用\跟八进制或十六进制数来表示字符,如:

\八进制数\141=a
\十六进制数\x61=a
\Unicode字符编码\5218=刘

和正则表达式一样,如果不想用反斜杠\转义,在字符串前加“r”,如:

# 字符串
s = r'\nhello world\n'  
print(s)    # \nhello world\n
# 正则
r = r'^\d+\n$'    # 可以匹配到123\n,78\n

1.4 运算

常见的字符串运算符:

比较运算符:==,!=,>,<,>=,<=,

连接运算符:+,+=,*,

成员运算符:in,not in,

索引和切片:[i],[a:b:step]

演示:

str1 = '123'
str2 = '456'
print(str1 * 2)
# '123123'
print(str1 + str2)
#'123456'
str1 += str2
print(str1)
# '123456'
print('1' in str1)
# True
print('6' not in str1)
# False
print(str1[1])
# 2
# 切片:前含后不含
print(str1[0:3]) # 123
print(str1[1:5:2]) # 24
print(str1[-2:-1]) # 56
print(str1[-4:-1:2]) # 35
#比较
print(str1==str2) # False
print(str1!=str2) # True
print(str1>=str2) # False
print(str1<=str2) # True
print(str1>str2) # False
print(str1<str2) # True

1.5 处理

常见的格式:str.函数名(),练习:

str1 = 'abc123'
# 计算字符长度
print(len(str1)) # 6
# 计算字节长度(汉字GBK算2,utf-8算3)
print(len(str1.encode())) # 6
# 判断是否只包含数字
print(str1.isdigit()) # False
# 判断是否只包含字母
print(str1.isalpha()) # False
# 是否只包含字母或数字
print(str1.isalnum()) # True
# 获得字符串首字母大写的拷贝
print(str1.capitalize()) # Abc123
# 获得字符串全部单词首字母大写的拷贝
print(str1.title()) # Abc123
# 获得字符串全部大写的拷贝
print(str1.upper()) # ABC123
# 获得字符串全部小写的拷贝
print(str1.lower()) # abc123
# 查找子串:find/rfind
print(str1.find('a')) # 找到时,返回索引,0
print(str1.find('s')) # 找不到时,返回-1
# 查找子串:index/rindex
print(str1.index('a')) # 找到时,返回索引,0
# print(str1.index('s')) # 找不到会报错
# 所以最好跟if搭配使用
if 's' in str1:
    print(str1.index('s'))
# 查找子串出现次数
print(str1.count('a',0,3)) # 1
# 检查是否以某字符开头
print(str1.startswith('a')) # True
# 检查是否以某字符结尾
print(str1.endswith('a')) # False
# 将字符串以指定宽度居中并在两侧填充指定字符
print(str1.center(50,'-'))
# 将字符串以指定宽度靠右对齐并在左侧填充指定字符
print(str1.rjust(50,'-'))
# 将字符串以指定宽度靠左对齐并在右侧填充指定字符
print(str1.ljust(50,'-'))
# 获取字符串修剪两侧空格后的拷贝strip/rstrip/lstrip
str2 = '  abc   '
print(str2.strip()) # abc
# 字符串连接
print(str1+''+str2) # abc123 abc
# 连接字符串列表
list1 = ['abcd','123','456']
str3 = '-'.join(list1)
print(str3) # abcd123456
# 字符串替换
print(str1.replace('ab','cc')) # ccc123
print(str1.replace('a','c',1)) # cbc123 #1 只替换一次,字符串第一次出现该字符时替换
print(str1.replace('a',' ').replace('c','b')) # 链式替换 bb123
# 字符串分割
print(str1.split('b')) # ['a','c123']
# 字符串截取
print(str1[1]) # b
print(str1[1:3]) # bc
print(str1[0:5:2]) # a c 2

1.6 格式化输出

有三种字符串格式化的方法,假设x=3,y=5:

方法写法结果版本
%print('a=%d,b=%d' % (x,y))a=3,b=5传统方法

str.format

print('a={},b={}'.format(x,y))a=3,b=53.1版本后
f-stringprint(f'a={x},b={y}')a=3,b=53.6版本后

二、列表、元组、集合、字典

2.1 比较

列表元组字典集合
英文listtupledictionaryset
格式list=['','']tuple=('',)dict={'':'','':''}set={'',''}
特性值可变值不可变key唯一不可变,value可变值唯一,可计算
创建

a. list=[]

b. list(range(8))

,list(其他对象)

同列表

a. dict(zip

(list1,list2))

b. dict(key1

=value1,key2

=value2)

c. dict={list1:list2}

a. set={}

b. set(可迭代对象),如range对象,列表,元组,创建后值去重

访问

print(list[2])

print(list[:2])

同列表

a.print(dict[key])

b.print(dict.

get(key))

-
遍历

a. for i in list:

    print(i)

b. for i in range(len(list)):

    print(list[i])

c. for index,i in enumerate(list):

    print(index,i)

同列表

a. 获取键值对

for i in dict.items():

    print(i)

b. 获取键值

for key,value in dict.items():

    print(key,value)

-
修改list[2]='abc' # 重新给指定index赋值

tuple=('a',) 

tuple=('b',) # 重新给元组赋值

dict[old_key]

=new_value

# 重新给指定key赋值

-
添加

a.list.append(i)

b. list1.extend(

list2)

tuple1= tuple1+tuple2

# 在元组末尾加上新元组

dict[new_key]

=new_value

set.add('1')
删除

a. del list[-1]

b. if i in list:     list.remove(i)

-

a. del

if key in dict:

    del dict[key]

a. del

b. remove()

c. pop()

d. clear()

排序

a. 默认升序list.sort(key=len

,reverse=True)

b. 生成新list sorted(list,key=,

reverse=False)

---
计算

sum(list) # 统计数值列表元素和

min(list)/max(list) # 求列表中最值

list.count(i) # 统计i出现次数

list.index(i) # 求i的下标

--

set1 & set2交集

set1 | set2

并集

set1 - set2

差集

set1 ^set2

对称差集

推导式

① list=[i ** 2 for i in range(10)]

② list=[i ** 2 for i in list2]

③ list=[i ** 2 for i in list if i > 0]

④ 使用生成器对象: a=(i ** 2 for i in range(10))

print(list(a)) # 可以转化为列表,也可以转化为元组,比①②③占用内存小

① 使用生成器对象: 

a=(i ** 2 for i in range(10))

print(tuple(a))

# 遍历生成器对象:

a. for i in a:

   print(i)

b. print(

a.__next__())

① dict={i:j for i,j in zip(list,list1)} # 列表生成字典

② dict={i:j for i in range(9) for j in range(4)}

③ dict={i,j for i,j in dict1 if j >0} #字典生成字典

-

补充:yield关键字定义生成器

使用yield定义的函数被称为生成器函数。当调用生成器函数时,它不会立即执行,而是返回一个迭代器。每次从这个迭代器请求一个值时(通常是通过next()函数或for...in循环),生成器函数会执行到下一个yield语句,并产出该语句的值。当函数执行完毕或遇到return语句时,生成器结束。(引用自“百度AI会话”)

def f():
    for i in range(1,10):
# 函数变为生成器函数
        yield i 
# 创建一个生成器对象
g = f() 
print(g)
# 从迭代器请求值
for i in g:
    print(i) # 1 2 3 4 5 6 7 8 9
# 或使用next()函数,每次可以请求一个值
print(g.__next__()) # 1

2.2 转化

a = [1,2,3]
b = [4,5,6]
# list-tuple 相互转化
a1 = tuple(a)
b1 = tuple(b)
# list/tuple-dict 列表元组可以转化为字典
c = dict(zip(a,b))
d = dict(zip(a1,b1))
# list/tuple-set 列表元组可以转化为集合
e = set(a)
f = set(a1)

2.3 二维列表

2.3.1 创建

a. 直接定义

list = [[1,2,3],[4,5,6],[7,8,9]] 

b. for循环

list = []
for i in range(4):
    list.append([]) # 在list中生成i个空列表
    for j in range(5):
        list[i].append(j) # 在子列表i中加入元素j
# [[0,1,2,3,4],[0,1,2,3,4],[0,1,2,3,4],[0,1,2,3,4]]

c. 列表推导式

list = [(j for j in range(5)) for i in range(4)]
# [[0,1,2,3,4],[0,1,2,3,4],[0,1,2,3,4],[0,1,2,3,4]]

2.3.2 访问

# list[i][j],第i行第j个,i,j表示下标,从0开始
print(list[1][3]) # 第2行第4个
# 2

三、练习

3.1 在屏幕上显示跑马灯文字

import os
import time
def light():
    content = '生而无畏,战至终章'
    while True:
        # 先清屏
        os.system('cls') #Unix和Linux系统用clear
        print(content)
        # 休眠200毫秒
        time.sleep(0.2)
        # 每行提前1字符的内容,形成跑马灯效果
        content = content[1:] + content[0]


if __name__ == '__main__':
    light()

3.2 设计一个函数产生指定长度的验证码,验证码由大小写字母和数字构成

import random

def yzm(length=4):
    """
    生成指定长度的验证码,不指定默认为4
    return: 验证码
    """
    # 定义一个空字符串
    yz = ''
    # 验证码包含大小写字母和数字
    x = [chr(i) for i in range(48,58)] # chr(48)-chr(57)是数字0-9的ASCII编码
    y = [chr(i) for i in range(65,91)] # chr(65)-chr(90)是数字A-Z的ASCII编码
    z = [chr(i) for i in range(97,123)] # chr(97)-chr(122)是数字a-z的ASCII编码
    # a是包含A-Za-z0-9的列表
    a = x + y + z
    # 循环4次,从列表中随机取数
    for i in range(length):
        index = random.randint(0,len(a)-1) #随机获取一个索引
        yz += a[index] 
        # 删除列表中已经取过的数,确保验证码不同位数不重复
        # a.pop(index) 
    return yz


if __name__ == '__main__':
    print(yzm())

补充:random库常见函数

import random

random.random():
# 返回[0.0, 1.0)之间的随机浮点数。
random.randint(a, b):
# 返回在[a, b]范围内的随机整数,其中a <= b。
random.randrange(start, stop, step):
# 返回在[start, stop)范围内的随机整数,步长为step。
random.choice(seq):
# 从非空序列seq中随机选择一个元素。
random.sample(population, k):
# 从population序列中随机选择k个不重复的元素,以列表形式返回。

3.3 设计一个函数返回给定文件名的后缀名

def hz(filename,has_dot=False):
    """
    返回指定文件名的后缀名
    filename:文件名
    has_dot:返回的后缀名是否需要带点
    return:后缀名
    """
    if '.' in filename:
        # 如果文件有后缀名,拆分文件名
        filelist = filename.split('.')
        # 截取文件名拆分后的列表的最后一位
        print(filelist[-1] if not has_dot else '.'+filelist[-1])
    else:
        print('')


if __name__ == '__main__':
    hz('1.txt')
# 方法2
def hz(filename,has_dot=False):
    """
    返回指定文件名的后缀名
    filename:文件名
    has_dot:返回的后缀名是否需要带点
    return:后缀名
    """
    # 从右侧开始查找filename第一次出现.的位置,默认.右边的部分就是后缀名
    site = filename.rfind('.')
    # 如果查找结果不等于-1,说明.存在,截取.之后的部分
    if site in range(0,len(filename)-1):
        index = site if has_dot else site+1 #自右计算的索引,加1默认左移一位
        print(filename[index:])
    else:
        print('')


if __name__ == '__main__':
    hz('1.txt')

3.4 设计一个函数返回传入的列表中最大和第二大的元素的值

def top2(list1):
    """
    获取传入列表中的最大和第二大元素
    :param list1:输入list内容,如:[1,2,3,4,5,6]
    :return: list中最大和第二大的元素
    """
    for i in range(2):
        a = max(list1)
        print(a)  # 获取当前列表的最大值
        list1.remove(a)  # 删除本次获取的最大值


if __name__ == '__main__':
    list1 = [1,2,3,4,5,6]
    top2(list1)
方法2:
def top2(l):
    m1,m2 = (l[0],l[1]) if l[0]>l[1] else (l[1],l[0])
    for i in range(2,len(l)):
        if l[i]>m1:
            m2 = m1
            m1 = l[i]
        elif m1>l[i]>m2:
            m2 = l[i]
    return m1,m2


if __name__ == '__main__':
    print(top2([1,2,3,4,5,6,7,8])) # tuple

3.5 计算指定的年月日是这一年的第几天

def is_leap_year(year):
    """
    函数用于判断某年是不是闰年,如果年份除以4可以整除但除以100不能整除就是闰年,或者年份可以整除400也是闰年,
    :param year: 要判断的年份
    :return: 如果是闰年,返回1
    """
    if (year % 4 ==0 and year % 100 != 0) or year % 400 == 0:
        return 1

def which_day(year,month,day):
    """
    函数用于计算某个具体年月日是当年的第几天
    :param year: 年
    :param month: 月
    :param day: 日
    :return: 当年的第几天
    """
    big = [31,28,31,30,31,30,31,31,30,31,30,31] # 大月
    # 闰年大于2月加1,闰年1月,2月正常按day算入,不受影响
    num = (sum(big[0:month])+1) if (is_leap_year(year) == 1 and month >2) else sum(big[0:month])
    # 当月月份的天数多算了,比如一月,之前算了big[0:0],已经算了31天,需要把多算的减去
    total = num-(big[month-1] - day)
    return total


if __name__ == '__main__':
    print(which_day(2020, 2, 29))  # 60
    print(which_day(2023, 4, 28))  # 118
    print(which_day(2020, 1, 28))  # 28
    print(which_day(2020, 4, 28))  # 119
# upgrade_vision
def is_leap_year(year):
    """
    函数用于判断某年是不是闰年,如果年份除以4可以整除但除以100不能整除就是闰年,或者年份可以整除400也是闰年,
    :param year: 要判断的年份
    :return: 如果是闰年,返回1
    """
    return (year % 4 ==0 and year % 100 != 0) or year % 400 == 0 #返回一个等式是否成立的布尔值,True or False

def which_day(year,month,day):
    """
    函数用于计算某个具体年月日是当年的第几天
    :param year: 年
    :param month: 月
    :param day: 日
    :return: 当年的第几天
    """
    days = [[31,28,31,30,31,30,31,31,30,31,30,31],
            [31,29,31,30,31,30,31,31,30,31,30,31]][is_leap_year(year)]
    # is_leap_year(year)是索引,返回True即调用index=1的子序列,2月=29
    total = 0
    for i in range(month-1):
        total += days[i]
    return total + day


if __name__ == '__main__':
    print(which_day(2020,2,29)) # 60
    print(which_day(2023,4,28)) # 118
    print(which_day(2020,1,28)) # 28
    print(which_day(2020,4,28)) # 119

3.6 打印杨辉三角

# vision 1.1
def main():
    row_number = int(input('please input row_number'))
    num = []
    for i in range(row_number):
        num.append([])
        # 每行第一个数字必是1
        num[i].append(1)
        # 从第二行开始
        if i >=1 :
            # i=1,range(2),j=1,j是第i行的索引,但i-1行不一定存在,所以不存在我们就作为0
            # 为什么从1开始是因为j=0开始j-1就等于-1了,会额外多加上上一序列的最后一个值
            for j in range(1,len(num[i-1])+1):
                try:
                    a = num[i-1][j]
                except IndexError: #如果i-1列表中,索引j不存在,直接默认=0
                    a = 0
                try:
                    b = num[i-1][j-1]
                except IndexError: #如果i-1列表中,索引j不存在,直接默认=0
                    b = 0
                num[i].append(a + b)
    # 循环列表,输出元素
    for i in range(row_number):
        for j in range(len(num[i])):
            print(num[i][j],end='\t')
        print()


if __name__ == '__main__':
    main()
# vision 1.2
def main():
    num = int(input('请输入行数'))
    main = [[]] * num
    for i in range(num):
        # 用None先占位,灵活运用列表乘法
        main[i] = [None] * (i+1)
        for j in range(len(main[i])):
            if j == 1 or j == len(main[i])-1:
                # 每行第一个和最后一个数字都等于1
                main[i][j] = 1
            else:
                main[i][j] = main[i-1][j] + main[i-1][j-1]
            print(main[i][j],end='\t')
        print()


if __name__ == '__main__':
    main()
# vision 1.3
def main():
    num = int(input('请输入行数: '))
    # 使用列表推导式来正确创建 main 列表
    main = [[0] * (i + 1) for i in range(num)]
    
    for i in range(num):
        for j in range(i + 1):
            if j == 0 or j == i:
                # 每行第一个和最后一个数字都等于1
                main[i][j] = 1
            else:
                # 其他位置是上一行相邻两个数字的和
                main[i][j] = main[i - 1][j - 1] + main[i - 1][j]
        # 打印当前行的所有数字
        print('\t'.join(map(str, main[i])))

# 调用 main 函数
main()

3.7 设计一个函数返回斐波拉切数列前20个值

def qblq(i):
    a,b = 0,1
    for i in range(i):
        a,b = b,a+b # 递归 b=a+b,b上轮的b,a是上上轮的b
        yield a

def main():
    for i in qblq(20):
        print(i,end=' ')

if __name__ == '__main__':
    main()

# 递归常见案例:阶乘 n! = n * (n-1)!,当 n > 0,0! = 1
def factorial(n):
    if n == 0:  # 基本情况
        return 1
    else:  # 递归情况
        return n * factorial(n-1)
    
print(factorial(4))

四、综合练习

4.1 双色球选号

4.2 约瑟夫环问题

"""
《幸运的基督徒》
有15个基督徒和15个非基督徒在海上遇险,为了能让一部分人活下来不得不将其中15个人
扔到海里面去,有个人想了个办法就是大家围成一个圈,由某个人开始从1报数,报到9的
人就扔到海里面,他后面的人接着从1开始报数,报到9的人继续扔到海里面,直到扔掉15
个人。由于上帝的保佑,15个基督徒都幸免于难,问这些人最开始是怎么站的,哪些位置
是基督徒哪些位置是非基督徒。
"""

4.3 井字棋游戏

  • 6
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值