字符串的驻留机制
#
# 主题:字符串的驻留机制
#
if __name__ == '__main__':
# 不可变序列:元组、字符串
# 驻留机制:
# 对于相同的字符串,只保留一份拷贝,
# 后续创建相同字符串时,不会开辟新空间,而是把该字符串的地址赋给新创建的变量
a = 'python'
b = "python"
c = '''python'''
print(id(a)) # 1430903362144
print(id(b)) # 1430903362144
print(id(c)) # 1430903362144
# 驻留机制的前提条件
# 驻留机制在 python 原编译器中会出现,而在后续的集成环境中,如 PyCharm,就不会发生
# PyCharm 对字符串进行了优化
# 可以在命令行中输入 python 并回车,进入交互式 python,之后输入下列代码验证
# 1. 字符串的长度为 0 或 1
a = 'a'
b = 'a'
print(id(a)) # 1610197355576
print(id(b)) # 1610197355576
# 符合驻留机制的条件
# 2. 符合标识符的字符串,即字符串中只有数字、字母、下划线
# 3. 字符串只在编译时进行驻留,而不是运行时
a = 'abc'
b = 'ab' + 'c' # 在编译时连接字符串
c = ''.join(['ab', 'c']) # 在运行时,调用 join 方法,然后连接字符串
print(a is b) # 符合驻留条件
print(a is c) # 不符合驻留条件
# 4. [-5, 256] 之间的整数数字也可发生驻留
# sys 包中的 intern 方法强制两个字符串指向同一个对象
import sys
a = 'ab%'
b = 'ab%'
print(a is b) # False
a = sys.intern(b)
print(a is b) # True
# 字符串驻留机制的优点
# 优点:
# 当需要值相等的字符串时,可以直接从字符串池里拿来使用,避免频繁地创建和校徽,提升效率和节约内存
# 注意
# 拼接、修改字符串是比较影响性能的
# 拼接字符串时,建议使用字符串的 join 方法,而不是 +
# join 方法先计算出所有字符串的长度,然后拷贝。这样,就 new 一次对象,效率比 + 高
字符串的查询操作的方法
#
# 主题:字符串的查询操作的方法
#
if __name__ == '__main__':
s = 'hello, hello'
# index 方法
# 查找子字符串第一次出现的位置,若不存在,则报错 ValueError
print(s.index('lo')) # 3
# find 方法
# 查找子字符串第一次出现的位置,若不存在,则返回 -1
print(s.find('lo')) # 3
# rindex 方法
# 查找子字符串最后一次出现的位置,若不存在,则报错 ValueError
print(s.rindex('lo')) # 10
# rfind 方法
# 查找子字符串最后一次出现的位置,若不存在,则返回 -1
print(s.rfind('lo')) # 10
# 推荐使用 find 方法和 rfind 方法
字符串的大小写转换
#
# 主题:字符串的大小写转换
#
if __name__ == '__main__':
s = 'hello, python'
s1 = 'Hello, Python'
# 字符串中所有字符都转成大写字母
a = s.upper()
print(s, id(s)) # hello, python 2250561907376
print(a, id(a)) # HELLO, PYTHON 2250561907312
# upper 方法生成新对象
# 字符串中所有字符都转成小写字母
b = a.lower()
print(a, id(a)) # HELLO, PYTHON 3022125492656
print(b, id(b)) # hello, python 3022125492784
# lower 方法生成新对象
# 字符串中所有大写字母转成小写字母,把所有小写字母都转成大写字母
c = s1.swapcase()
print(s1, id(s1)) # Hello, Python 1664029387440
print(c, id(c)) # hELLO, pYTHON 1664029434800
# swapcase 方法生成新对象
# 第一个字符转为大写,其余字符转换为小写
d = s.capitalize()
print(s, id(s)) # hello, python 2055284947312
print(d, id(d)) # Hello, python 2055284990704
# capitalize 方法生成新对象
# 字符串中每个单词的第一个字符都转为大写,其余字符都转为小写
e = s.title()
print(s, id(s)) # hello, python 2003960162928
print(e, id(e)) # Hello, Python 2003960210480
字符串内容对齐
#
# 主题:字符串内容对齐
#
if __name__ == '__main__':
s = 'hello, python'
# 居中对齐
# 第1个参数指定宽度,第2个参数指定填充符,第2个参数可选,默认是空格,若设置宽度小于实际宽度则返回原字符串
print(s.center(20, '*')) # ***hello, python****
print(s.center(20)) # hello, python
print(s.center(10, '#')) # hello, python 返回原字符串
# 左对齐
# 第1个参数指定宽度,第2个参数指定填充符,第2个参数可选,默认是空格,若设置宽度小于实际宽度则返回原字符串
print(s.ljust(20, '*')) # hello, python*******
print(s.ljust(20)) # hello, python
print(s.ljust(10)) # hello, python 返回原字符串
# 右对齐
# 第1个参数指定宽度,第2个参数指定填充符,第2个参数可选,默认是空格,若设置宽度小于实际宽度则返回原字符串
print(s.rjust(20, '*')) # *******hello, python
print(s.rjust(20)) # hello, python
print(s.rjust(10)) # hello, python 返回原字符串
# 右对齐
# 左边用0填充,该方法只接收一个参数,用于指定字符串的宽度,若指定的宽度小于字符串的长度,返回字符串本身
print(s.zfill(20)) # 0000000hello, python
print(s.zfill(10)) # hello, python 返回原字符串
s1 = '-800'
print(s1.zfill(10)) # -000000800
字符串劈分(分割)操作
#
# 主题:字符串劈分(分割)操作
#
if __name__ == '__main__':
s = 'hello world python'
# 从字符串左边开始分割,默认的分割字符是空格字符串,返回的结果的类型是 list
# 通过参数 sep 指定分割字符串的字符
# 通过参数 maxsplit 指定分割字符串时最大的分割次数,在经过最大次分割之后,剩余的子串会单独作为一部分
lst = s.split() # 默认以空格分割
print(lst) # ['hello', 'world', 'python']
print(s.split(sep = 'o')) # ['hell', ' w', 'rld pyth', 'n']
print(s.split(sep = 'o', maxsplit = 2)) # ['hell', ' w', 'rld python']
# 从字符串右边开始分割,默认的分割字符是空格字符串,返回的结果的类型是 list
# 通过参数 sep 指定分割字符串的字符
# 通过参数 maxsplit 指定分割字符串时最大的分割次数,在经过最大次分割之后,剩余的子串会单独作为一部分
lst = s.rsplit() # 默认以空格分割
print(lst) # ['hello', 'world', 'python']
print(s.rsplit(sep='o')) # ['hell', ' w', 'rld pyth', 'n']
print(s.rsplit(sep='o', maxsplit=2)) # ['hello w', 'rld pyth', 'n']
字符串的判断操作
#
# 主题:字符串的判断操作
#
if __name__ == '__main__':
s = 'hello, python'
# 判断字符串是否为合法标识符
print('1', s.isidentifier()) # False
# isidentifier 方法判断是否为合法标识符
# 合法标识符相关规定详见第1章
print('2', '张三'.isidentifier()) # True
# 判断字符串是否全部由空白字符(如回车、换行、水平制表符)组成
print('3', '\t'.isspace()) # True
# 判断字符串是否全部由字母组成
print('4', 'hello'.isalpha()) # True
print('5', 'hello,'.isalpha()) # False
print('6', 'hello张三'.isalpha()) # True
# 判断字符串是否全部由十进制数字组成
print('7', '123'.isdecimal()) # True
print('8', '123四'.isdecimal()) # False
print('9', 'ⅠⅡⅢ'.isdecimal()) # False
# 判断字符串是否全部由数字组成
print('10', '123'.isnumeric()) # True
print('11', '123四'.isnumeric()) # True
print('12', 'ⅠⅡⅢ'.isnumeric()) # True
# 判断字符串是否全部由字母和数字组成
print('13', 'abc1'.isalnum()) # True
print('14', '张三123'.isalnum()) # True
print('15', 'abc!'.isalnum()) # False
字符串的替换和合并
#
# 主题:字符串的替换和合并
#
if __name__ == '__main__':
s = 'hello,python,python,python'
# 替换字符串
# 第1个参数指定被替换的子字符串,第2个参数指定替换子字符串的字符串,第3个参数指定最大替换次数(可选)
# 返回替换后得到的字符串,替换前的字符串不发生变化
s1 = s.replace('python', 'java')
s2 = s.replace('python', 'java', 2)
print(s1, id(s1)) # hello,java,java,java 2958341037272
print(s, id(s)) # hello,python,python,python 2958340910016
print(s2) # hello,java,java,python
# replace 方法返回新对象
# 合并字符串
# 将列表或元组中的字符串合并为一个字符串
# join 方法返回新对象
lst = ['hello', 'java', 'python']
out = '|'.join(lst)
print(lst, id(lst)) # ['hello', 'java', 'python'] 2537298027080
print(out, id(out)) # hello|java|python 2537305168464
t = ('hello', 'java', 'python')
print(''.join(t)) # hellojavapython
print('*'.join('python')) # p*y*t*h*o*n
字符串的比较
#
# 主题:字符串的比较
#
if __name__ == '__main__':
# 用到的运算符:>, >=, <, <=, ==, !=
# 比较规则:首先比较两个字符串中的第一个字符,如果相等则继续比较下一个字符,依次比下去,
# 直到两个字符串中的字符不相等时,其比较结果就是两个字符串的比较结果,其余字符不会继续比较
# 比较原理:比较字符时,比较的是其原始值,调用 ord 方法可以得到指定字符的原始值
# 调用 chr 方法可以得到原始值对应的字符
print('apple' > 'app') # True
print('apple' > 'banana') # False
print(ord('a'), ord('b')) # 97 98
print(chr(97), chr(98)) # a b
print(ord('杨')) # 26472
print(chr(26472)) # 杨
# == 是判断是否值相等,is 是判断是否地址相等
a = b = 'python'
c = 'python'
print(a == b) # True
print(b == c) # True
print(a is b) # True
print(a is c) # True
字符串的切片操作
#
# 主题:字符串的切片操作
#
if __name__ == '__main__':
# 字符串是不可变类型,故不具备增删改操作。切片操作产生新对象
s = 'hello,python'
s1 = s[:5]
s2 = s[6:]
s3 = '!'
newStr = s1 + s3 + s2
print(s1) # hello
print(s2) # python
print(newStr) # hello!python
# 完整写法 [start: end: step]
print(s[0:5:1]) # hello
print(s[::2]) # hlopto
print(s[::-1]) # nohtyp,olleh
print(s[-6::1]) # python
格式化字符串
#
# 主题:格式化字符串
#
if __name__ == '__main__':
# % 作占位符
# %s 对应字符串,%i 或 %d 对应整数,%f 对应浮点数
name = '张三'
age = 20
print('我是%s,今年%d岁' % (name, age)) # 我是张三,今年20岁
print('%10d' % 99) # 99 其中,10 表示宽度
print('%f' % 3.1415926) # 3.141593
print('%.3f' % 3.1415926) # 3.142 其中,.3 表示小数点后三位,即精度
print('%10.3f' % 3.1415926) # 3.142
# {} 作占位符
print('我叫{0},今年{1}岁'.format(name, age)) # 我叫张三,今年20岁
print('{0:.3}'.format(3.1415926)) # 3.14 其中,.3 表示的是一共是三位数
print('{0:.3f}'.format(3.1415926)) # 3.142 其中,.3f 表示的是3位小数
print('{:.3f}'.format(3.1415926)) # 3.142
print('{:10.3f}'.format(3.1415926)) # 3.142 其中,10表示宽度
# print('{1:10.3f}'.format(3.1415926)) # 冒号前面的是索引,对应的是format()中的元素
# f-string 即,f'字符串' 格式
print(f'我叫{name},今年{age}岁') # 我叫张三,今年20岁
字符串的编码转换
#
# 主题:字符串的编码转换
#
if __name__ == '__main__':
# 编码:字符串转换为二进制数据(bytes)
# 解码:bytes 类型的数据转换为字符串类型
# 二进制数据用于数据传输
s = '天涯共此时'
# 编码
print(s.encode(encoding = 'GBK')) # b'\xcc\xec\xd1\xc4\xb9\xb2\xb4\xcb\xca\xb1'
# 在 GBK 编码方式中,一个中文占2个字节
print(s.encode(encoding = 'utf-8')) # b'\xe5\xa4\xa9\xe6\xb6\xaf\xe5\x85\xb1\xe6\xad\xa4\xe6\x97\xb6'
# 在 utf-8 编码中,一个中文占3字节
# 解码
# byte 代表一个二进制数据(字节类数据)
# GBK 编码得到的数据必须使用 GBK 解码,utf-8编码得到的数据必须使用 utf-8 解码
byte = b'\xcc\xec\xd1\xc4\xb9\xb2\xb4\xcb\xca\xb1'
byte1 = b'\xe5\xa4\xa9\xe6\xb6\xaf\xe5\x85\xb1\xe6\xad\xa4\xe6\x97\xb6'
print(byte.decode(encoding = 'GBK')) # 天涯共此时
print(byte1.decode(encoding = 'utf-8')) # 天涯共此时