Python3内置数据结构学习2-字符串

python

Python3内置数据结构

    本篇是对Python3内置数据结构的初步学习与小结,用于复习巩固使用,如有理解偏差的地方,还望各位大佬指正。


字符串

字符串定义

  • 字符串str是 Python 中最常用的数据类型。

    • 一个个字符组成的有序的序列,是字符的集合
    • 使用单引号、双引号、三引号包住的字符序列
    • 有序序列可索引
    • 不可变类型
      • str1[2] = ‘s’ 直接报错
      • 字符串的各种运算操作,并非是修改字符串,比如字符串的拼接其实就是覆盖命名一个新的字符串。

字符串初始化

字符串初始化后,其本身不可改变。

s1 = 'string'			## 最直接定义
s2 = "str‘i’ng2"		## 用""可以在内部继续使用‘’
s3 = '''this's a 
		"String" 
	 ''' 				## ‘’‘ 可以在内部放‘’及””,还可以换行
s4 = 'hello \n magedu.com'  ## 转义符\ \n是newline
s5 = 'hello \\n magedu.com' ## \\n 多家一个转义符吧\本身转义
s6 = r"hello \n magedu.com" ## 字符串前写r,取消转义,常用于正则表达式


字符串转义符

  • 字符串中存在着一些特殊字符:
    • 特殊字符就是在字符串当中起到特殊含义的字符
    • “\” 转义符 将字符串转义符后面的紧跟的特殊字符的特殊含义取消掉,或者在行尾作为续行符
符号意义
\ (在行尾时)换行
\\反斜杠符号
\’单引号
\"双引号
\a响铃
\b退格
\e转义
\000
\n换行
\v纵向制表符
\t横向制表符
\r回车
\f换页

字符串元素访问

    字符串是有序的字符序列,索引方法与列表相似。

  • 字符串支持使用索引访问,与列表相似:
    • 索引的用法,取单个元素时,使用字符串[索引值] 索引值为对应元素的索引号;
    • 字符串截取:字符串[start:end],得到对应索引范围的元素,该范围是左闭右开的,默认截取的方向是从左往右的,反取:字符串[负数],会变成反向从右往左取;
    • 步长截取:字符串[start?step] 按照 step步长截取,step默认为1;
      • 若 step > 0, 则表示从左向右切片,start 必须小于 end 才有结果,否则为空。
      • 若 step < 0, 也是表示从左到右,但是 start 必须大于 end 才有结果,就变成了反向切片,否则为空。
sql = "select"
sql[4] # 字符串'c'
# sql[4] = 'o' # 字符串是不可变类型,直接报错
sql[0:4]
sql[0:5:2]
sql[::-1] # 省略会按顺序取到最后一位,不会报错也不会少取
c
'sele'
'slc'
'tceles'
  • 字符串是有序的字符集合,字符序列:
for c in sql[:5]:
	print(type(c), c)
<class 'str'> s
<class 'str'> e
<class 'str'> l
<class 'str'> e
<class 'str'> c
  • 字符串是可迭代对象:
    经常用list方法将字符串转化成列表。
lst = list(sql)
['s', 'e', 'l', 'e', 'c', 't']

字符串连接

字符串join连接
  • 字符串join连接
    “string”.join(iterable) -> str
  • 该join方法常用于列表转字符串,返回一个字符串
    • 将可迭代对象连接起来,使用string作为分隔符。
    • 可迭代对象本身元素都是字符串。
    • 返回一个新字符串。
lst = ['1','2','3']
print("".join(lst)) # 将列表元素无缝组合成一个字符串
print("+++".join(lst)) # 使用666作为分隔符
123
1+++2+++3

字符串 + 连接
  • 字符串+连接
    str + str -> str
    • 将2个字符串连接在一起
    • 返回一个新字符串
str1 = 's'
print(str1, id(str1))
str1 = str1 + 'r'  # 
print(str1, id(str1))
s  2781397991640
sr 2781443149248

注意:字符串是不可变类型,没有原对象的修改方式,但是为了方便,允许使用类似重写的方式,用 + 连接字符串,这样使用起来就像是可以修改一样,但是我们查看ID就可以发现已经变量名不是原字符串对象。


字符串分割

  • 分割字符串的方法主要有2大类
    • split系
      • 将字符串按照分隔符分割成若干字符串,并返回列表。
    • partition系
      • 将字符串按照分隔符分割成2段,返回这2段和分隔符的元组。
字符串分割split
  • split(sep=None, maxsplit=-1) -> list of strings
    • 从左向右。
    • sep 指定分割字符串,缺省的情况下空白字符串作为分隔符。
    • maxsplit 指定分割的最大次数,默认为-1 表示遍历整个字符串,贪婪匹配,尽可能多。
s1 = "I'm \ta super man."
print(s1.split())    # 切空字符串
print(s1.split('s')) # 按分隔符‘s’,贪婪匹配
print(s1.split(' ',maxsplit=2)) # 按分隔符空白分隔符,贪婪匹配
["I'm", 'a', 'super', 'man.']
["I'", ' \ta super ', 'an.']
["I'm", '\ta', 'super man.']


  • rsplit(sep=None, maxsplit=-1) -> list of strings
    • 从右向左。
    • sep 指定分割字符串,缺省的情况下空白字符串作为分隔符。
    • maxsplit 指定分割的次数,默认为-1 表示遍历整个字符串,贪婪匹配,尽可能多。
s1 = "I'm \ta super man."
print(s1.rsplit()) 
print(s1.rsplit('m'))  
print(s1.rsplit(' ',maxsplit=2))  # 从右向左切
print(s1.rsplit('m',maxsplit=1))  # 从右向左切
["I'm", 'a', 'super', 'man.']
["I'", ' \ta super ', 'an.']
["I'm \ta", 'super', 'man.']
["I'm \ta super ", 'an.']

  • splitlines([keepends]) -> list of strings
    • 按照行来切分字符串,返回一个包含各行作为元素的列表。
    • keepends 指的是是否保留行分隔符。
    • 行分隔符包括\n、\r\n、\r等。
s1 = "I'm\n \ta\r\n super \nman."
print(s1.splitlines())
print(s1.splitlines(True))  # 保留行分隔符
["I'm", ' \ta', ' super ', 'man.']
["I'm\n", ' \ta\r\n', ' super \n', 'man.']

注意:

  • 如果字符串中没有split切割符完全对应的子字符串,则返回的列表也就只有一个元素,即字符串本身。
  • split切割不保留分隔符。

字符串分割partition
  • partition(sep) -> (head, sep, tail)
    • 从左至右,遇到分隔符就把字符串分割成两部分,返回头、分隔符、尾三部分的三元组。
    • 如果没有找到分隔符,就返回头、2个空元素的三元组。
    • sep 分割字符串,必须指定。
s1 = "I'm\n \ta\r\n super \nman."
print(s1.partition('\r'))   # 从左往右切成三部分
print(s1.partition('\rnn')) # 没找到分隔符,也返回三元素列表
("I'm", '\n', ' \ta\r\n super \nman.')
("I'm\n \ta\r\n super \nman.", '', '')
  • rpartition(sep) -> (head, sep, tail)
    • 从右至左,遇到分隔符就把字符串分割成两部分,返回头、分隔符、尾三部分的三元组。
    • 如果没有找到分隔符,就返回2个空元素和尾的三元组。
    • sep 分割字符串,必须指定。
s1 = "I'm\n \ta\r\n super \nman."
print(s1.rpartition('\n'))   # 从右往左切成三部分
print(s1.rpartition('\rnn')) # 没找到分隔符,也返回三元素列表
("I'm\n \ta\r\n super ", '\n', 'man.')
('', '', "I'm\n \ta\r\n super \nman.")

小结:

  • partition方法必须指定分隔符,不能缺省。
  • partition方法不管有没有找到分隔符,都飞返回3元组列表,即返回头、分隔符、尾三部分的三元组。

字符串修改

replace替换

replace方法用于替换字符串中的每种字符。

  • replace(old, new[, count]) -> str
    • 从左到右替换指定的元素。
    • 字符串中找到匹配替换为新子串,返回新字符串。
    • count指定替换次数,不指定就是全部替换。
s1 = "I'm \ta super man."
print(s1.replace('m','MM'))   # 替换字符
print(s1.replace('m','MM',1)) # 指定替换次数
I'MM 	a super MMan.
I'MM 	a super man.


strip去边
  • strip([chars]) -> str
    • 从字符串两端去除指定的字符集chars中的所有字符。
    • 如果chars没有指定,去除两端的空白字符。
    • 返回一个新的字符串。
    • lstrip([chars]) -> str
      • 从左开始。
    • rstrip([chars]) -> str
      • 从右开始。
s1 = " 09I'm \ta super man.0 09;"
print(s1.strip())    # 不指定字符集,就去掉空白字符
print(s1.strip(' 0912'))  # 从两边最外层开始,去除字符集中有的字符
print(s1.strip(' 9.011;')) # 字符集中的顺序无所谓
print(s1.lstrip(' 9.0;'))  # 只去掉左边
print(s1.rstrip(' 9.0;'))  # 只去掉右边

09I'm 	a super man.0 09;
I'm 	a super man.0 09;
I'm 	a super man
I'm 	a super man.0 09;
 09I'm 	a super man

小结:

  • strip非常适用于字符串两段杂质的清理,尤其是提供一个无序字符集,使用起来很方便。
  • 返回的是一个新的字符串。

字符串查找

find查找
  • find(sub[, start[, end]]) -> int
    • 在指定的区间[start, end),从左至右,查找子串sub。找到返回索引,没找到返回-1。
  • rfind(sub[, start[, end]]) -> int
    • 在指定的区间[start, end),从右至左,查找子串sub。找到返回索引,没找到返回-1。
s = "I am very very very sorry"
print(s.find('very')) 
print(s.find('very', 5)) # 从字符串的索引为5开始查找,匹配到就立刻返回首位索引值
print(s.find('very', 6, 8)) # 区间查找,没找到返回-1
print(s.rfind('very', 10))
print(s.rfind('very', 10, 15))
print(s.rfind('very', -10,-1)))
5
5
-1
15
10
15

小结:

  • find查找子串十分有用,可以方便的获得字符串的索引。
  • 子串如果不存在,find会返回-1,而不会直接报错,index则会直接报错。
  • 虽然查找看似很方便,但需要遍历字符串,也就是说时间复杂度是O(n)的,如果查找的子串不存在,则必定要遍历整个字符串,使用时需要慎重。
  • 有时候我们只想判断这个子串的是否存在,而不想要索引,则可以通过in方法。
    sub in str -> bool
    得到一个bool型判断值。

index查找
  • index(sub[, start[, end]]) -> int
    • 在指定的区间[start, end),从左至右,查找子串sub。找到返回索引,没找到抛出异常ValueError。
  • rindex(sub[, start[, end]]) -> int
    • 在指定的区间[start, end),从左至右,查找子串sub。找到返回索引,没找到抛出异常ValueError。
s = "I am very very very sorry"
s.index('very')
s.index('very', 5)
s.rindex('very', 10)     # 从指定的区间开始,从右往左查找
s.rindex('very', 10, 15) # 从指定的区间开始,从右往左查找
s.rindex('very',-10,-1)

s.index('very', 6, 8)  # 区间内子串不存在,直接报错
5
5
15
10
15

小结:

  • index查找与find查找基本一致,最大区别在于子串不存在时index会直接报错,因此除非业务需要,我们一般选用find查找。

count计数
  • count(sub[, start[, end]]) -> int
    • 在指定的区间[start, end),从左至右,统计子串sub出现的次数
s = "I am very very very sorry"
print(s.count('very'))    # 不指定子串区间,从左到右计数
print(s.count('very', 5)) # 指定子串区间,从左到右计数
print(s.count('very', 10, 14)) # 指定子串区间,从左到右计数
3
3
1

小结:

  • count计数对于很多业务而言的是必要的方法。
  • find, index, count 涉及遍历,时间复杂度为O(n)。随着列表数据规模的增大,而效率下降,在嵌套循环中使用性能下降尤为明显。
  • 有时可以利用已有的遍历实现计数,避免嵌套循环使用count方法。

字符串判断

字符串首尾判断
  • startswith(prefix[, start[, end]]) -> bool
    • 在指定的区间[start, end),字符串是否是prefix开头
  • endswith(suffix[, start[, end]]) -> bool
    • 在指定的区间[start, end),字符串是否是suffix结尾
s = "I am very very very happy"
print(s.startswith('am'))  # 从头开始,连续匹配子串
print(s.startswith('am', 2))
print(s.startswith('very', 5, 9))
print(s.endswith('very', 5, 9)) # 从尾开始,连续匹配子串
print(s.endswith('happy', 5))
print(s.endswith('happy', 5, -1))
print(s.endswith('happy', 5, 100)) # 区间超界也可以
False
True
True
True
True
False
True

小结:

  • 首尾判断,对于处理一些格式的字符内容,非常方便,配合strip使用效果更佳。
  • 由于只判断首尾,效率很高,推荐使用。
字符串is判断
判断方法判断内容
isalnum判断字符串是否完全由字母戒数字组成
isalpha判断字符串是否完全由字母组成
isdigit判断字符串是否完全由数字组成
isupper判断字符串当中的字母是否完全是大写
islower判断字符串当中的字母是否完全是小写
istitle判断字符串是否满足 title 格式
isspace判断字符串是否完全由空格组成
'12345a'.isalnum()
'adcdef'.isalpha()
'123456'.isdigit()
'HellO'.isupper()
True
True
True
False

小结:

  • 使用is方法判断字符串是否符合内容要求,是业务常用方法,很多时候,我们需要判断输入的字符串是什么类型,是否符合要求。

字符串排版

方法字符串内容格式化修改
upper将字符串当中所有的字母转换为大写
lower将字符串当中所有的字母转换为小写
swapcase将字符串当中所有的字母大小写互换
title标题化,将单词首字母大写,单词以非字母划分
capitalize只有字符串的首字母大写
expandtabs把字符串中的制表符号(’\t’)转为空格,(’\t’)默认的空格数是 8
'hello'.upper()
'Hello'.swapcase()
'hello world'.title()
'for\tis\tcool'.expandtabs(4)
'for\tis\tcool'.expandtabs()  # ‘\t’ 变成空白符,默认8个
'HELLO'
'hELLO'
'Hello World'
'for is  cool'
'for     is      cool'

字符串格式化

  • 字符串的格式化是一种拼接字符串输出样式的手段,更灵活方便
    • join拼接只能使用分隔符,且要求被拼接的是可迭代对象且其元素是字符串。
    • + 拼接字符串还算方便,但是非字符串需要先转换为字符串才能拼接。
printf-style formatting
  • 在2.5版本之前,只能使用printf style风格的print输出
    • printf-style formatting,来自于C语言的printf函数。
    • 格式要求
      • 占位符:使用%和格式字符组成,例如%s、%d等。
        • s调用str(),r会调用repr()。所有对象都可以被这两个转换。
      • 占位符中还可以插入修饰字符,例如%03d表示打印3个位置,不够前面补零。
      • format % values,格式字符串和被格式的值之间使用%分隔。
      • values只能是一个对象,或是一个与格式字符串占位符数目相等的元组,或一个字典。
"I am %03d" % (20,)
'I like %s.' % 'Python'
'%3.2f%% , 0x%x, 0X%02X' % (89.7654, 10, 15)
"I am %-5d" % (20,)
'I am 020'
'I like Python.'
'89.77% , 0xa, 0X0F'
'I am 20   '

小结

  • printf-style formatting 是C语言风格的字符串格式化,大部分C系列的语言都支持这种格式化风格。
  • Python有自己的字符串格式化方法,format函数更优雅,功能更强大,推荐使用。

format函数-- 推荐使用
  • format函数格式字符串语法——Python风格推荐使用

    • ="{} {xxx}".format(*args, **kwargs) -> str
    • args是可变位置参数,是一个元组,用于位置赋值。
    • kwargs是可变关键字参数,是一个字典,用于关键字赋值。
    • 花括号表示占位符。
    • {}表示按照顺序匹配位置参数,{n}表示取位置参数索引为n的值。
    • {xxx}表示在关键字参数中搜索名称一致的。
    • {{}} 表示打印花括号,如果有多余的位置参数,会送到里面的{}中嵌套传参。
  • 位置参数

    • 按照位置顺序用位置参数替换前面的格式字符串的占位符中。
    "{}:{}".format('192.168.1.100',8888)
    

    '192.168.1.100:8888'

  • 关键字参数或命名参数

    • 位置参数按照序号匹配,关键字参数按照名词匹配。
    "{server} {1}:{0}".format(8888, '192.168.1.100', server='Web Server Info : ') 
    

    'Web Server Info : 192.168.1.100:8888'

  • 访问元素

    • 通过索引访问参数元素。
    "{0[0]}.{0[1]}".format(('xxx','com'))
    

    'xxx.com'

    • 这种情况一般可以直接参数解构,转变成位置参数。
    "{}.{}".format(*('xxx','com'))
    

    'xxx.com'

  • 对象属性访问

    • 通过format函数传入对象,并调用该对象的方法 。
    from collections import namedtuple
    Point = namedtuple('Point','x y')
    p = Point(4,5)
    print("{{{0.x},{0.y}}}".format(p))
    

    {4,5}

  • 格式化对齐

    • 字符串面向人类的数据类型,这时候打印的格式化问题就很重要。format提供了强大的字符格式化方法,包括居中,居左,居右,填充,占位等。
'{0}*{1}={2:<2}'.format(3,2,2*3)  # 居左打印位置参数2
'{0}*{1}={2:>04}'.format(3,2,2*3) # 居右打印位置参数2,填充0
'{:^30}'.format('centered')  # 居中打印
'{:*^30}'.format('centered') # 居中打印,填充*
'3*2=6 '
'3*2=0006'
'            center            '
'************center************'
  • 进制打印
    • 利用format函数,将参数格式化为X进制显示。
"int: {0:d}; hex: {0:x}; oct: {0:o}; bin: {0:b}".format(42) # 不打印进制标志符
"int: {0:d}; hex: {0:#x}; oct: {0:#o}; bin: {0:#b}".format(42) # 不打印进制标志符

octets = [192, 168, 0, 1]
'{:#02X}|{:02X}|{:02X}|{:02X}'.format(*octets) # 参数解构填充,并按大写十六进制打印
'int: 42; hex: 2a; oct: 52; bin: 101010'
'int: 42; hex: 0x2a; oct: 0o52; bin: 0b101010'

'0XC0|A8|00|01'
  • 浮点数
    • 与C风格相似,Python风格的format函数也可以对浮点型数据进行精细的格式化打印。

print("{}".format(3**0.5)) # 1.7320508075688772
print("{:f}".format(3**0.5)) # 1.732051,精度默认6
print("{:10f}".format(3**0.5)) # 右对齐,宽度10
print("{:2}".format(102.231)) # 宽度为2
print("{:.2}".format(3**0.5)) # 1.7 2个数字
print("{:.2f}".format(3**0.5)) # 1.73 小数点后2位
print("{:3.2f}".format(3**0.5)) # 1.73 宽度为3,小数点后2位
print("{:3.3f}".format(0.2745)) # 0.275
print("{:3.3%}".format(1/3)) # 33.333%

1.7320508075688772
1.732051
  1.732051
102.231
1.7
1.73
1.73
0.275
33.333%

format格式化经典–九九乘法表

  • 打印九九乘法表
    • 九九乘法表是个练习循环与格式化打印的经典案例
for i in range(1, 10):
    for j in range(1, i + 1):    # 控制循环
        sub = i * j
        space = '  ' if j > 1 and sub < 10 else ' ' #控制个数数间距
        print('{}*{}={}'.format(j, i, sub), end= space) #格式化打印
    print('')  # 每次循环结束补一个回车

1*1=1 
1*2=2 2*2=4  
1*3=3 2*3=6  3*3=9  
1*4=4 2*4=8  3*4=12 4*4=16 
1*5=5 2*5=10 3*5=15 4*5=20 5*5=25 
1*6=6 2*6=12 3*6=18 4*6=24 5*6=30 6*6=36 
1*7=7 2*7=14 3*7=21 4*7=28 5*7=35 6*7=42 7*7=49 
1*8=8 2*8=16 3*8=24 4*8=32 5*8=40 6*8=48 7*8=56 8*8=64 
1*9=9 2*9=18 3*9=27 4*9=36 5*9=45 6*9=54 7*9=63 8*9=72 9*9=81 

总结:

  • 对于同一业务,可以有多重格式化方法,重点在于是否可以灵活的使用格式化函数,而这就需要在学习使用中不断的积累。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值