Python 字符串

前言

​ 本章节将针对于Python3的字符串,关于Python2的字符串将在其他文章中指出。

字符串

​ Python中的字符串,类型是str。

基本声明

​ 以下是使用类的形式进行声明:

string = str("HELLO,WORLD")
print("值:%s,类型%s"%(string,type(string)))
# 值:HELLO,WORLD,类型<class 'str'>

​ 也可以选择使用更方便的字面量形式:

string = "HELLO,WORLD"
print("值:%s,类型%s"%(string,type(string)))
# 值:HELLO,WORLD,类型<class 'str'>

关于字面量形式声明,你可以使用英文状态下的单引号,也可以使用双引号。

此外,虽然单三引号与双三引号都可以进行字符串声明,但是并不推荐,因为它们还具有注释的语义存在。

类型转换

​ 字符串支持与bool和int以及float进行转换:

string = "100"
i_string = int(string) # 整形
b_string = bool(string) # 布尔类型
f_string = float(string) # 浮点型

print("值:%s,类型%s"%(i_string,type(i_string)))
print("值:%s,类型%s"%(b_string,type(b_string)))
print("值:%s,类型%s"%(f_string,type(f_string)))

# 值:100,类型<class 'int'>
# 值:True,类型<class 'bool'>
# 值:100.0,类型<class 'float'>

​ 需要注意的是,如果一个字符串不是纯数字,那么将其转换为整形或浮点型时将会出现异常:

string = "非纯数字:100"
i_string = int(string) # 整形
f_string = float(string) # 浮点型

print("值:%s,类型%s"%(i_string,type(i_string)))
print("值:%s,类型%s"%(f_string,type(f_string)))

# ValueError: invalid literal for int() with base 10: '非纯数字:100'

​ 此外,字符串也支持转换为list以及set:

string = "一零二四"
set_string = set(string)  # 集合类型
list_string = list(string)  # 列表类型

print("值:%s,类型%s"%(set_string,type(set_string)))
print("值:%s,类型%s"%(list_string,type(list_string)))

# 值:{'二', '零', '一', '四'},类型<class 'set'>
# 值:['一', '零', '二', '四'],类型<class 'list'>

​

四则运算

​ 字符串支持与字符串相加,做到拼接的效果:

s1 = "字符串1"
s2 = "字符串2"
print(s1 + s2)
# 字符串1字符串2

​ 字符串支持与整形相乘,做到重复打印的效果:

s1 = "*"
print(s1 * 3)
# ***

​ 除此之外的运算均不支持:

print("--- " - "222")
# TypeError: unsupported operand type(s) for -: 'str' and 'str'

其他特性

​ 字符串是原子类型,即字符串无法修改。这是由于字符串底层是连续存储导致的。

​ 此外字符串虽然是属于容器类型,可以容纳多个单字符,但字符串的传递更多的并非引用传递,而是值传递。

索引切片

概念介绍

​ 底层是顺序存储的容器类型都具有索引的概念:

---------------------------------------|
| A | B | C | D | E | F | G |
---------------------------------------|
| 0 | 1 | 2 | 3 | 4 | 5 | 6 |
|-7 |-6 |-5 |-4 |-3 |-2 |-1 |

​ 正向索引都是从0开始,负向索引都是从-1开始。

slice()函数

​ slice()函数有三个参数。

​

参数介绍 描述
start 索引开始的位置
stop 索引结束的位置
step 步长间距

​ 使用方法如下示例,先规定切的范围,然后使用[]进行包裹:

s1 = "abcdefg"
# 取出 a
s = slice(0, 1, None)
print(s1[s]) # a 取索引0,到1结束,取头0,不取尾1

注意:所有的切片都是顾头不顾尾。

​ 如果我们想从s1中拿到子串bcde则可以进行下面这样切:

s1 = "abcdefg"
s = slice(1, 5, None)
print(s1[s]) # bcde

​ 如果想隔着切,如aceg,则可以指定步长:

s1 = "abcdefg"
s = slice(0, None, 2) # 比如:a开始,b是第一个,c是第二个,拿c ,以此类推
print(s1[s]) # aceg

[::]形式

​ 使用slice()函数会比较繁琐,直接使用[::]的形式会比较简单。

​ 使用签名如下:

[start:stop:step]

​ 参数描述和slice()相同,当某一参数不设置时可省略前面的:。

​ 需要注意的是,如果使用[:]则代表将当前容器重新进行拷贝。

s1 = "abcdefg"
s2 = s1[:]
print("值:%s,地址:%s"%(s1,id(s1)))
print("值:%s,地址:%s"%(s2,id(s2))) 

# 值:abcdefg,地址:1240503058984
# 值:abcdefg,地址:1240503058984

# 如果是str使用[:]将不会生成新对象,而是引用原本对象。如果是其他数据类型进行[]则会生成新对象

正向切片

​ 正向切片即使用正向索引,索引从0开始进行切片。

​ 如下示例:

s1 = "abcdefg"
print(s1[1:3]) # bc

反向切片

​ 反向切片即使用反向索引,索引从-1开始进行切片。

s1 = "abcdefg"
print(s1[-3:-1]) # ef

混合使用

​ 反向和正向切片可以混合使用,下面是一些高级切片的用法。

# --- str 除开 [:] 其他的取值都是生成新对象,list和tuple的取值不管怎样都是生成新对象

s1 = "hello,world"

# hello,world 如果对str类型使用这种操作.等同于 s2 = s1 ,内存地址引用都是相同的.而对于list和tuple来说则是浅copy.生成新对象。
s2 = s1[:]

s3 = s1[3:7]  # lo,w 取头不取尾,生成新的一段字符串(list,tuple同理)

s4 = s1[::2]  # hlowrd 隔一个取一个,步长为2。

s5 = s1[::-1]  # dlrow,olleh 反取,步长为负数

s6 = s1[::-2]  # drwolh 倒过来,隔一个取一个.

s7 = s1[:-6:-2]  # drw  倒过来.截至 -6 结束,隔着位置取。

s8 = s1[0::-1]  # h  倒着取,正着数到第零个开始取,也就是h,唯一 一个就是这个h了,取到头了,就拿出h。没啥好说的。

s9 = s1[5::-2]  # ,le 倒着取,开始位置是正着数到第五个 也就是,开始。再看结束位置,没有代表取到头。跳着来

常用方法

获取长度

​ 使用len()来进行长度的获取。

​ 返回int类型的值。

s1 = "abcdefg"
print(
    len(s1) # 7
)

移除空白

​ 使用strip(str)移除字符串两侧指定的字符,如不进行指定,则默认移除\n、\t以及空格。

​ 返回str类型的值。

s1 = "   abcdefg   $$$"
res = s1.strip(" $")
print(res)

拆分列表

​ 使用split(char,int)按照指定字符进行从左到右的分割,以列表形式返回。可指定maxslipt限制切分次数。

​ 使用rsplit(char,int)按照指定字符进行从右到左的分割,以列表形式返回。可指定maxslipt限制切分次数。

​ 返回list类型的值。

s1 = "ab,cd,ef,gh"
res = s1.split(",",maxsplit=1)
print(res) 
# ['ab', 'cd,ef,gh']
s1 = "ab,cd,ef,gh"
res = s1.rsplit(",",maxsplit=1)
print(res) 
# ['ab,cd,ef', 'gh']

列表合并

​ 使用join(li)将一个列表中的元素以指定字符拼接成新的字符串。

​ 返回str类型的值。

l1 = ["a","b","c"]
res = "-".join(l1)
print(res)
# a-b-c

替换操作

​ 使用replace(str,str)将字符串中的指定子串替换成另一个子串。

​ 返回str类型的值。

s1 = "ABCDEFG"
res = s1.replace("BCD","bcd")
print(res)
# AbcdEFG

统计子串

​ 使用count(str)统计子串在父串中出现的次数。

​ 返回int类型的值。

s1 = "HELLO"
res = s1.count("L")
print(res)
# 2

词首大写

​ 使用title()令字符串中的每一个单词首字母大写。

​ 返回str类型的值。

s1 = "hello world"
res = s1.title()
print(res)
# Hello World

句首大写

​ 使用capitalize()令字符串中的句首单词变为大写。

​ 返回str类型的值。

s1 = "hello world"
res = s1.capitalize()
print(res)
# Hello world

查找位置

​ 使用find(str)查找子串出现在父串中的索引值,若存在则返回索引,若不存在则返回-1。

​ 返回int类型的值。

s1 = "hello world"
res = s1.find("w")
print(res)
# 6

小写转大写

​ 使用upper()令字符串中所有的小写字母转换为大写。

​ 返回str类型的值。

s1 = "hello world"
res = s1.upper()
print(res)
# HELLO WORLD

大写转小写

​ 使用lower()令字符串中所有的大写字母转换为小写。

​ 返回str类型的值。

s1 = "HELLO WORLD"
res = s1.lower()
print(res)
# hello world

指定开头

​ 使用startswith(str)判断字符串是否以子串开头。

​ 返回bool类型的值。

s1 = "HELLO WORLD"
res = s1.startswith("HE")
print(res)
# True

指定结尾

​ 使用endswith(str)判断字符串是否以子串结束。

​ 返回bool类型的值。

s1 = "HELLO WORLD"
res = s1.endswith("LD")
print(res)
# False

数字串

​ 使用isdigit()判断该字符串是否是一个数字串。

​ 返回bool类型的值。

s1 = "100"
res = s1.isdigit()
print(res)
# True

其他方法

​ 以下是一些其他不太常用的方法:

方法名 描述
index(str) 同find(),唯一区别找不到抛出异常,find()是返回-1
center(int,str) 指定宽度,指定字符。若字符串的长度不够则将字符串放在中间,两侧使用指定字符填充
ljust(int,str) 指定宽度,指定字符。若字符串的长度不够则将字符串放在左边,右侧使用指定字符填充
rjust(int,str) 指定宽度,指定字符。若字符串的长度不够则将字符串放在右边,左侧使用指定字符填充
zfill(int) 同rjust(),但是不可指定填充字符。按0进行填充
swapcase() 字符串中大小进行翻转。大写转小写,小写转大写。
expandtabs(int) 指定字符串中的tab长度,\t代表制表符
isdecimal() 查看字符串是否由数字组成。只支持unicode并且没有bytes的使用
isnumeric() 查看字符串是否由数字组成。只支持unicode,中文数字,罗马数字并且没有bytes的使用
isalnum() 字符串中既可以包含数字也可以包含字母
isalpha() 字符串中只包含字母
islower() 判断字符串是否纯小写
isupper() 判断字符串是否纯大写
istitle() 判断字符串中的单词是否首字母大写
isspace() 判断字符串是否全是空格
# ==== str的了解操作 ====

# === 以下方法均不会改变原本str中的值,而是生成一个新的对象返回 ===

s2 = "hello,world"
print(s2.index("hel"))  # 0 同find(),唯一区别找不到抛出异常,find()是返回-1
print(s2.center(20, "+"))  # ++++hello,world+++++ center代表居中,算上原本的hello,world一共要凑齐20的长度,如果不够则在两边添加符号 + 。原本的字符占中间
print(s2.ljust(20, '+'))  # hello,world+++++++++ ljust,l代表left,同上。left规定原本字符占左边
print(s2.rjust(20, '+'))  # +++++++++hello,world rjust,r代表right,同上。right规定原本字符占右边
print(s2.zfill(20))  # 000000000hello,world 同rjust,但是自动填充0而不是指定的字符。
print(s2.swapcase())  # HELLO,WORLD 字符串中的大小写翻转


s3 = "hello,\tyunya!" # \t 代表 tab  制表符。
print(s3)  # hello,    yunya! 默认tab宽度为1个空格
print(s3.expandtabs(6))  # hello,      yunya!  修改字符串中的tab宽度为6个空格。

# ======= Python3 中 is系列之 判断纯数字组成的str三种方法 推荐:isdigt()=======

num1 = b'4' #bytes 代表字节。
num2 = u'4' #unicode,python3中无需加u就是unicode。
num3 = '四' #中文数字
num4 = 'Ⅳ' #罗马数字

#isdigt()查看字符串是否是由数字组成。只支持bytes和unicode
print(num1.isdigit()) # True

print(num2.isdigit()) # True

print(num3.isdigit()) # False

print(num4.isdigit()) # False

#isdecimal()查看字符串是否由数字组成。只支持unicode并且没有bytes的使用。
print(num2.isdecimal()) # True

print(num3.isdecimal()) # False

print(num4.isdecimal()) # False

#isnumeric()。只支持unicode,中文数字,罗马数字并且没有bytes的使用。
print(num2.isnumeric()) # True

print(num3.isnumeric()) # True

print(num4.isnumeric()) # True

# ======= 以上3种方法均不支持浮点型str的判断,全部为False =======

# ======= is 系列其他的一些方法 =======
name = 'yunya696969'

print(name.isalnum()) # True 字符串中既可以包含数字也可以包含字母
print(name.isalpha()) # False 字符串中只包含字母
print(name.isidentifier()) # True 判断字符串是否是符合Python变量命名标准。(数字字母下划线)
print(name.islower()) # True 判断字符串是否纯小写
print(name.isupper()) # False 判断字符串是否纯大写
print(name.istitle()) # False 判断字符串中的单词是否首字母大写
print(name.isspace()) # False 判断字符串是否全是空格

转义输出

特殊的\

​ 在普通的声明字符串中,\后面一般都会跟上一个特殊字符。

​ 该字符表示特殊的意义,如\n代表换行,\t代表制表符等。

​

转义字符 意义 ASCII码值(十进制)
\a 响铃(BEL) 007
\b 退格(BS) ,将当前位置移到前一列 008
\f 换页(FF),将当前位置移到下页开头 012
\n 换行(LF) ,将当前位置移到下一行开头 010
\r 回车(CR) ,将当前位置移到本行开头 013
\t 水平制表(HT) (跳到下一个TAB位置) 009
\v 垂直制表(VT) 011
\ 代表一个反斜线字符''' 092
\' 代表一个单引号(撇号)字符 039
\" 代表一个双引号字符 034
? 代表一个问号 063
\0 空字符(NUL) 000
\ddd 1到3位八进制数所代表的任意字符 三位八进制
\xhh 十六进制所代表的任意字符 十六进制

​ 如果你还是不能理解,那么可看一下下面这个示例:

# 我想打印  hello"world
# 并且我的字符串声明采用 “

print("hello\"world")
# 必须进行转义,否则将会抛出语法错误

r字符串

​ 如果在声明字符串的前面加上字符r,则代表该字符串中不会存在转义字符,所有字符将按照普通的方式进行解读。

s1 = r"\n\t\b"
print(s1)
# \n\t\b

格式化输出

​ 如果我们想在字符串中加入一个变量值,则需要用到格式化输出。

%

​ %格式化的历史悠久,很多码龄较长的程序员都喜欢用它进行格式化输出。

​ 我们来看一个例子:

name = "云崖先生"
age = 19
s1 = "姓名是:%s,年龄是:%d"%(name,age) # ①
print(s1)
# 姓名是:云崖先生,年龄是:19

​ 其中,①处注释在字符串中的%s、%d等都是占位符,学习%的格式化输出首先要了解占位符的使用。

占位符 描述
%s 接收任意类型的值,以字符串形式显示
%r 接收任意类型的值,以r字符串形式显示
%c 只接收单个字符
%b 接收int类型的值,二进制整数形式显示
%d 接收int类型的值,十进制整数形式显示
%i 接收int类型的值,十进制整数形式显示
%o 接收int类型的值,八进制整数形式显示
%x 接收int类型的值,十六进制整数形式显示
%e 接收float类型的值,指数形式显示 (基底写为e)
%E 接收float类型的值,指数形式显示 (基底写为E)
%f 接收float类型的值,浮点数形式显示
%F 接收float类型的值,浮点数形式显示
%g 接收float类型的值,指数(e)或浮点数 (根据显示长度)
%G 接收float类型的值,指数(E)或浮点数 (根据显示长度)

​ 位置传参

​ 一个%对应一个变量名。

​ 当变量名有多个时便需要%后面跟上括号做解包,如若只有一个则不需要加上括号,% 和后面的 %(a,b,c)位置一一对应:

name = "云崖先生"
age = 19
s1 = "姓名是:%s,年龄是:%d"%(name,age) 

​ 关键字传参

​ 变量名存储变量值内存地址引用。关键字传参打破位置顺序必须统一的限制:

name = "云崖先生"
age = 19
s1 = "姓名是:%(name)s,年龄是:%(age)d"%{"age":age,"name":name}

​ 格式化%分号

​ 如果想打印%多少,则可以使用下面的方式

​ %%百分号代表一个% 。放在 %d 后面的%则代表格式化出后的结果是3%:

s1 = "%d%%"%3 
print(s1) # 3%

format()

​ %虽然能够满足基本需求。但是其位置传参还是显得太过麻烦,故在Python2.6中新增format() 方法,它更加强大以及速度更快。

​ 推荐今后使用format()的方法进行字符串格式化 。

​ 注意:format()中的s只接受str类型的传值而不接受全部类型

位置传参

name = "yunya"
age = 18
s1 = "姓名是{:s},年龄是{:d}".format(name,age)
# 采用{}进行占位,需要注意的是format中的s不是接收全部类型的参数,而是指定str

# s1 = "姓名是{:s},年龄是{:d}".format(name,age)
# 也可不指定类型。默认接收全部类型参数

# 姓名是yunya,年龄是18

索引传参

name = "yunya"
age = 18
s1 = "姓名是{1:d},年龄是{0:s}".format(name, age)  
# 采用{}进行占位,无法使用s接收age。且format()中没有i

# s1 = "姓名是{1},年龄是{0}" .format(name,age)

# 姓名是yunya,年龄是18

关键字传参

name = "yunya"
age = 18
s1 = "姓名是{name:s},年龄是{age:d}".format(name=name, age=age) 
# 采用{}进行占位,无法使用s接收age。且format()中没有i

# s1 = "姓名是{name},年龄是{age}" .format(name=name,age=age)

# 姓名是yunya,年龄是18

字符填充

print('{0:*<10}'.format('|||'))  # < 代表字符 ||| 在左边,填充符号为 * 排在右边 一共10 个( 算上字符三个 | )
print('{0:%>10}'.format('|||'))  # > 代表字符 ||| 在右边,填充符号为 % 排在左边 一共10 个 ( 算上字符三个 | )
print('{0:$^10}'.format('|||'))  # ^ 代表字符 ||| 在中间,填充符号为 $ 排在两侧 两侧加起来共10个 ( 算上字符三个 | )
print('{0:$=10}'.format(123))    # = 代表数字 123 在右边,填充符号为 $ 排在左边 一共10个 Ps: = 只针对数字 ( 算上字符123 )

# |||*******
# %%%%%%%|||
# $$$|||$$$$
# $$$$$$$123

精度控制与格式转换

print('{0:.2f}'.format(3.1415926535))  # f代表接收值类型为float类型,.2代表小数点后保留2位
print('{0:b}'.format(10))  # 转换为二进制 b
print('{0:x}'.format(10))  # 转换为十六进制 x
print('{0:o}'.format(10))  # 转换为八进制 o
print('{0:,}'.format(1000000))  # 千分位表示 ,
print('{0:.2%}'.format(1))  # 百分号表示  2代表2位数,转换数据1 为 百分之百
print('{0:.2%}'.format(0.3))  # 百分号表示
print('{{{0}}}'.format('笑脸')) # 显示大括号。 外部套2层大括号

# 3.14
# 1010
# a
# 12
# 1,000,000
# 100.00%
# 30.00%
# {笑脸}

f

尽管format()已经非常方便了。但是如果传入的参数值太多依旧会看着十分混乱,于是Python3.6中新增了 f 格式字符串的操作。

这种方法的速度最快,但是却不推荐使用,因为程序还要考虑一个向下兼容性的问题。

name = "yunya"
age = 18

s1 = f'我的名字叫做{name},我的年龄是{age}岁。'  # f 开头。 {} 为占位符用于存放变量名。
print(s1)
# 其他的关于高级操作如填充字符,精度控制与格式转换等等均与format()操作方式一样。

底层存储

​ 字符串本身是属于原子容器类型,即不可被修改。

​ 当尝试修改一个字符串时,它始终会返回给你一个新的字符串,而其他的容器类型如list等都不会重新返回新的。

​ 这是由于字符串底层的排列方式导致的。

s1 = "abc"
print(id(s1))  # 2601680846048
s1 += "def"
print(id(s1))  # 2601681784032

如果修改一个字符串的子串,比如添加或者删除。

因为字符串是连续的一块内存存放,被看做为一个整体,修改其中某一个元素那么必定会导致后面的内存发生变化,链式反应滚起雪球需要处理的数据量很庞大,于是Python干脆不支持使用index为字符串进行修改。

s1 = "abc"
print(id(s1))
s1[1] = "B"
print(id(s1))
# TypeError: 'str' object does not support item assignment

img

posted @ 2020-10-17 21:28  云崖君  阅读(194)  评论(0)    收藏  举报