一.字符串的表示方式
- 双引号或者单引号中的数据,就是字符串
- 如果使用一对引号来定义字符串,当出现符号冲突时可以使用转义字符
- 使用三个单引号、双引号定义的字符串可以包裹任意文本
二.字符串的赋值和地址问题
- s1、s2、s3的地址相同 / s4的地址不同
s1 = 'hello'
s2 = s1 #s1将地址赋给s2,这样s1和s2指向的是常量池中同一个字符串
s3 = "hello" #hello这个字符串在常量池中已经存在,所以将地址给s3,那么s3和s1、s2地址相同
s4 = 'hello1' #常量池中没有hello1这个字符串,会在常量池中新开辟一个地址,赋给s4
id(变量):id()函数用于将变量的内存地址得到转化为我们能看懂的地址
变量a is 变量b:is用于比较地址是否相同
- 当没有任何指针指向字符串,字符串就会被回收
三.字符串的索引机制
-
正向取索引(str = 'abcde')
0 ~ len(str)-1
从左到右索引依次为:0 1 2 3 4
-
反向取索引
-len(str) ~ -1
从右往左索引依次为:-1 -2 -3 -4 -5
有时候字符串长度很长,如果正向去取会很麻烦,但是如果倒着取,那么倒数第一个字符下标就为-1,向左依次为-2、-3、-4...
四.字符串相关操作
1.获取字符串长度
- len(字符串)
2.截取指定字符串
-
依据字符串索引机制,按索引取
str = 'abcdef' print(str[1]) #b print(str[-2]) #e
3.截取多个字符串(切片)
-
切片用于字符串和列表
-
格式:
字符串变量[start:end:step]
- 步长省略
-
[start:end] #左闭右开
-
正向索引
str = 'abcde' print(str[1:3]) #bc
-
反向索引
str = 'abcde' print(str[-4:-2]) #bc 也是左闭右开
-
正反索引可以混用
str = 'abcde' print(str[1:-2]) #bc
-
-
[:end] #默认从0开始
str = 'abcde' print(str[:3]) #abc print(str[:-1]) #abcd
-
[start:] #从start开始取到最后
str = 'abcde' print(str[2:]) #cde print(str[-2:]) #de
-
[:] #从头取到尾
str = 'abcde' print(str[:]) #abcde
注意:此时用切片的方式取出全部字符串和原字符串地址一样
-
list1[1:1] = [2,3] #比较特殊,根据底层原码大致理解为先看等号后面的列表长度n,然后再1:切片的位置之后含切片位置的所有元素后移n位,然后将等号后面的列表中的元素依次插入
list1 = [1,4] list1[1:1] = [2,3,{1,2},(1,2),{'a':1},'str'] print(list1) #[1, 2, 3, {1, 2}, (1, 2), {'a': 1}, 'str', 4]
注意只有列表的切片才能这样使用!!
- 加上步长
-
[start : end : step]
str = 'abcdef' print(str[1:-1:2]) #bdf
-
[ : end : step]
str = 'abcdef' print(str[:-1:3]) #ad
-
[start : : step]
str = 'abcdef' print(str[2::2]) #ce
-
[ : : step]
str = 'abcdef' print(str[::-1]) #fedcba print(str[::-2]) #fdb
-
[ : : : ]
str = 'abcdef' print(str[::]) #abcdef
注意:步长如果为正表示从左到右取,如果步长为负数表示从右往左反着取
而且一定注意:当步长为负数时,说明从右往左反着取,那么start的索引值一定要在end索引值的后面!!
-
易错举例:
str = 'abcdef' print(str[1:-1:-2]) #这样会取不到任何值!!!!因为step为-2表示倒着取,起始索引为1,倒着取下一个为 0,这样就永远到不了-1索引,所以取不到任何值 print(str[-1:1:-2]) #这样就可以取到值--fd (还是左闭右开) print(str[5::-1]) #从索引为5开始往前取--fedcba
4.查找(获取指定字符下标)
-
find:从左向右查找,只要遇到一个符合要求的则返回位置值。如果没有找到任何符合要求的则返回-1
path = 'https://www.baidu.com/img/dong_e39494cd9293c9d9cc9d0gk303945.gif' i = path.find('_') print(path[i+1:]) #取_后面的字符串 mystr = '今天天气好晴朗,处处好风光呀好风光' print(mystr.find('好风光')) #10 '好风光'第一次出现时,'好'所在的位置 print(mystr.find('风光',1,10)) #-1 从下标1开始到12查找"风光",未找到,返回 -1
-
rfind:类似于 find()函数,不过是从右边开始查找。如果没有找到任何符合要求的则返回-1
mystr = '今天天气好晴朗,处处好风光呀好风光' print(mystr.rfind('好')) #14
-
index:跟find()方法一样,只不过,find方法未找到时,返回-1,而str未找到时,会报一个异常
-
rindex:类似于 index(),不过是从右边开始。
5.判断
-
startswith:判断字符串是否以指定内容开始。
mystr = '今天天气好晴朗,处处好风光呀好风光' print(mystr.startswith('今')) # True
-
endswith:判断字符串是否以指定内容结束。
mystr = '今天天气好晴朗,处处好风光呀好风光' print(mystr.endswith('好风光')) #True
-
isalpha:判断字符串是否是纯字母
mystr = 'hello world' print(mystr.isalpha()) # False 因为中间有空格
-
isdigit:判断一个字符串是否是纯数字,只要出现非0~9的数字,结果就是False.
-
isalnum:判断是否由数字和字母组成。只要出现了非数字和字母,就返回False.
-
isspace:如果 mystr 中只包含空格,则返回 True,否则返回 False.
-
isupper:判断是否全部是大写字母
-
islower:判断是否全部是小写字母
6.统计出现次数
-
count:返回 str在start和end之间 在 mystr里面出现的次数。
mystr = '今天天气好晴朗,处处好风光呀好风光' print(mystr.count('好')) #3 '好'字出现三次
7.替换
- replace:替换字符串中指定的内容。如果没有指定次数则全部替换;如果指定次数count,则替换不会超过count次。
mystr = '今天天气好晴朗,处处好风光呀好风光'
newstr = mystr.replace('好', '坏')
print(mystr) # 今天天气好晴朗,处处好风光呀好风光 原字符串未改变!
print(newstr) # 今天天气坏晴朗,处处坏风光呀坏风光 得到的新字符串里,'好'被修改成了'坏'
newstr = mystr.replace('好','坏',2) # 指定了替换的次数
print(newstr) # 今天天气坏晴朗,处处坏风光呀好风光 只有两处的'好'被替换成了'坏'
注意:替换完的新字符串不会覆盖原字符串
- 疑问:如果要替换多个怎么办-------1.正则表达式 2.列表加循环 (后面会详解)
8.切割(分割字符串)
- split:以指定字符串为分隔符切片,如果 maxsplit有指定值,则仅分隔 maxsplit+1 个子字符串。返回的结果是一个列表。
mystr = '今天天气好晴朗,处处好风光呀好风光'
result = mystr.split() # 没有指定分隔符,默认使用空格,换行等空白字符进行分隔
print(result) #['今天天气好晴朗,处处好风光呀好风光'] 没有空白字符,所以,字符串未被分隔
result = mystr.split('好') # 以 '好' 为分隔符
print(result) # ['今天天气', '晴朗,处处','风光呀,'风光']
result = mystr.split("好",2) # 以 '好' 为分隔符,最多切割成3份
print(result) # ['今天天气', '晴朗,处处', '风光呀好风光']
- rsplit:用法和split基本一致,只不过是从右往左分隔。
- splitlines(了解):按照行分隔,返回一个包含各行作为元素的列表。
mystr = 'hello \nworld'
mystr = '''第一行
第二行
第三行
'''
print(mystr.splitlines())
- partition(了解):把mystr以指定str分割成三部分,str前,str和str后,三部分组成一个元组
mystr = '今天天气好晴朗,处处好风光呀好风光'
print(mystr.partition('好')) # ('今天天气', '好', '晴朗,处处好风光呀好风光')
- rpartition(了解):类似于 partition()函数,不过是从右边开始.
9.大小写转化
- title:每个单词的首字母大写。
mystr = 'hello world'
print(mystr.title()) # Hello World
- capitalize:第一个单词的首字母大写。
- upper:所有都变成大写。
- lower:所有都变成小写。
10.空格处理
-
strip:删除两端的空白字符
str = ' he llo ' print(str.strip()) #he llo
-
lstrip:删除 mystr 左边的空白字符
-
rstrip:删除 mystr 右边的空白字符
-
ljust:返回指定长度的字符串,并在右侧使用空白字符补全(左对齐)。
-
rjust:返回指定长度的字符串,并在左侧使用空白字符补全(右对齐)。
-
center:返回指定长度的字符串,并在两端使用空白字符补全(居中对齐)
str = 'hello' print(str.center(10)) # hello 两端加空格,让内容居中
11.字符串拼接
-
join:把参数进行遍历,取出参数里的每一项,然后再在后面加上mystr
一般用于列表--->返回一个字符串
mystr = 'a' print(mystr.join('hxmdq')) #haxamadaq 把hxmd一个个取出,并在后面添加字符a. 最后的q保留,没有加a print(mystr.join(['hi','hello','good'])) #hiahelloagood
-
+号:正常拼接字符串
12.字符串format格式化
-
概念
str.format()
方法通过字符串中的大括号{}
来识别替换字段replacement field
,从而完成字符串的格式化。 -
字段名的种类
-
1.省略字段名:
{}
注意:大括号个数可以少于位置参数的个数,反之不然
name = '小明' age = 18 print('我叫{},今年{}岁。'.format(name, age)) # 大括号个数可以少于位置参数的个数 print('我爱吃{}和{}。'.format('香蕉', '苹果', '大鸭梨')) # 大括号个数多于位置参数的个数则会报错 # print('我还吃{}和{}。'.format('西红柿')) """ IndexError: tuple index out of range """
-
2.使用非负十进制整数
{0}
-
数字必须是大于等于 0 的整数。
-
带数字的替换字段可以重复使用
# 数字形式的简单字段名可以重复使用。 name = '阿香' age = 17 print('我爱{0}。\n她今年{1}。\n我也爱{0}。'.format(name, age)) """ 我爱阿香。 她今年17。 我也爱阿香。 """
-
数字形式的简单字段名相当于把 format 中的所有位置参数整体当作一个元组,通过字段名中的数字进行取值。即 {0} 等价于 tuple[0],所以大括号内的数字不能越界。
# 体会把所有位置参数整体当成元组来取值 print('阿香爱吃{1}、{3}和{0}。'.format( '榴莲', '臭豆腐', '皮蛋', '鲱鱼罐头', '螺狮粉')) """ 阿香爱吃臭豆腐、鲱鱼罐头和榴莲。 """
-
-
3.变量名{name}
-
使用变量名形式的简单字段名传递关键字参数。
-
使用变量名关键字参数的位置可以随意调换。
-
但是注意:变量名做参数时一定要在format中赋值
# 关键字参数的顺序可以随意调换 print('我大哥是{name},今年{age}岁。'.format(age=20, name='阿飞')) """ 我大哥是阿飞,今年20岁。 """
-
-
4.简单字段名的混用
-
混合使用数字形式和变量名形式的字段名,可以同时传递位置参数和关键字参数。
-
关键字参数必须位于位置参数之后。
# 关键字参数必须位于位置参数之后 print('这是一个关于{0}、{1}和{girl}的故事。'.format( '小明', '阿飞', girl='阿香')) """ 这是一个关于小明、阿飞和阿香的故事。 """
-
混合使用时可以省略数字。
# 数字也可以省略 print('这是一个关于{}、{}和{girl}的故事。'.format( '小明', '阿飞', girl='阿香'))
-
省略字段名
{}
不能和数字形式的字段名{非负整数}
同时使用。# 但是省略字段名不能和数字形式的字段名同时出现 # print('这是一个关于{}、{1}和{girl}的故事。'.format( # '小明', '阿飞', girl='阿香')) """ ValueError: cannot switch from automatic field numbering to manual field specification """
-
-
例题1:利用切片和字符串方法
- 模拟上传文件,键盘输入上传文件的名称(不带后缀名),判断文件名是否大于6位以上,拓展名是否是:jpg、gif、png格式,如果不是则提示上传失败,如果名字不满足条件,而拓展名满足条件则随机生成一个6位数字组成的文件名,打印成功上传xxx.png等
import random
document = input('请输入上传文件名称:')
index = document.rfind('.')
if document.endswith('.jpg') or document.endswith('.gif') or document.endswith('.png'):
if len(document[index - 1::-1]) >= 6: #或者写[:index]
print('打印成功上传%s' % document)
else:
newName = random.randint(100000,999999) #randint()是左闭右闭的
print('打印成功上传%d%s' % (newName,document[index:]))
else:
print('格式不满足上传失败') 1748
改进:
- 随机生成一个由字母和数字组成的6位文件名 (很牛的方法--验证码就是这么来的)
filename = '' #表示filename是空的字符串类型的变量
s = 'abcdefghigklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890' #所有可能的情况
for i in range(6):
index = random.randint(0,len(s) - 1) #随机取一个整数,去表示s中的索引
filename += s[index] #将从s字符串中取出的元素拼接成6位字符串
print(filename)
例题2:字符串判断
'''
admin123 19182134110 123456
用户名或者手机号登录+密码
用户名:全部小写,首字母不能是数字,长度必须6位以上
手机号码:纯数字、长度11
密码必须是6位数字
以上符合条件则进入下层验证:
判断用户名+密码 是否正确,成功或失败
'''
flag = True
error = 0
while flag:
if error < 3:
name = input('请输入用户名或手机号:')
if (name.islower() and not name[0].isdigit() and len(name) > 6) or (name.isdigit() and len(name) == 11):
while error < 3:
password = input('请继续输入密码:')
if password.isdigit() and len(password) == 6:
if (name == '19182134110' or name == 'admin123') and password == '123456':
print('登录成功!')
flag = False
break
else:
print('账号或密码错误!(还有%d次尝试机会)' % (2 - error))
error += 1
break
else:
print('密码必须是6位!(还有%d次尝试机会)' % (2 - error))
error += 1
break
else:
print('用户名或手机输入格式错误')
else:
print('账号锁定!')
flag = False