《老鸟python 系列》视频上线了,全网稀缺资源,涵盖python人工智能教程,爬虫教程,web教程,数据分析教程以及界面库和服务器教程,以及各个方向的主流实用项目,手把手带你从零开始进阶高手之路!点击 链接 查看详情




再讲字符串

阅读:227569627    分享到

在前面基本数据类型一节我们学过字符串类型,字符串类型严格意义上来说不属于基本数据类型, 因为字符串是由多个单字符类型的数据组成的复合类型。

但 Python 不支持单字符类型,单字符在 Python 中也是作为一个字符串使用,这个和其它语言不同, Python 语言内置字符串类型,字符串是Python中最常用的数据类型之一。

我们本节课再次深入学习一下字符串的特点和函数,以及编码格式。

字符串元素的访问方式

字符串是有序集合,有序集合并不是集合里面的数据是有序的, 有序集合的意思是可以通过下标访问的集合。我们可以通过下标访问字符串,注意第一个元素是从下标 0 开始,越界访问 Python 解释器会报异常错误。

strone = "老鸟Python"
print(strone[0])
print(strone[100])  # 越界访问,会报异常

字符串是个常量,无论通过何种运算,都不会修改字符串本身的值, 我们不能通过该变量的索引修改它所指向的字符串内的字符, 但我们可以改变该变量指向的字符串。

strone = "老鸟Python"
strone[0] = "H"         # 错误,不可以修改字符串本身的值
strone = "Hello World"  # 正确,可以修改变量 strone 的指向
print(strone)

字符串运算

字符串支持一系列的运算,但遵守一定的规则,我们列举出常用的字符串运算,如下表格。

运算符 解释 运算规则
+ 字符串连接 只能是字符串和字符串相加
* 扩大字符串的倍数 只能是整数和字符串相乘(负整数和字符串相乘输出空字符串)
[] 通过索引访问字符串内元素 字符串本身
[:] 获取字符串的一部分并返回(不改变字符串本身) 字符串本身
in 如果字符串内含有给定的字符返回 True 否则 False 字符串本身
not in 如果字符串内不含有给定的字符返回 True 否则 False 字符串本身

重要的事情再说一遍,无论什么运算符操作字符串,都不会修改字符串本身的值。

strone = "Hello"
newstr = strone[0:3]  # 返回索引 0 到 3(不包含3)的子串
print(strone)
print(newstr)

操作字符串常用的函数

操作字符串的函数,有字符串本身内置的函数,也有非内置的函数, 这些函数可以对字符串进行一系列的操作,下面表格是字符串常用的一些函数。

函数 解释 性质
len 计算字符串的长度并返回(不是字节长度) Python 内置函数
find 字符串内查找子串,并返回子串首字母所在的索引,否则返回 -1 字符串自带函数
replace 字符串内查找子串并返回替换后的字符串 字符串自带函数
lower 把字符串内字符串内的所有字母变为小写并返回 字符串自带函数
upper 把字符串内字符串内的所有字母变为大写并返回 字符串自带函数

重要的事情说三遍,无论什么函数操作字符串,都不会修改字符串本身的值。

strone = "老鸟Python"
newstr = strone.replace("Python", "Hello")
print(strone)
print(newstr)

strtwo = "Hello World"
lowerstr = strtwo.lower()
print(strtwo)
print(lowerstr)

strthree = "Bird Python"
upperstr = strthree.upper()
print(strthree)
print(upperstr)

转义字符

在编程语言里,有很多特殊字符,它们起着各种各样的作用。 有些特殊字符没有办法用普通字符表示,需要进行转义。 python用反斜杠 \ 转义字符,下表列举了一些常用的需要转义的字符。

常用的转义字符 解释 适用方式
\ 反斜杠 单引号,双引号,三引号
\' 单引号 单引号,双引号,三引号
\" 双引号 单引号,双引号,三引号
\t 制表符 单引号,双引号,三引号
\n 换行 单引号,双引号,三引号

注意:Python 中可以用 r 来禁止字符转义,试一试下面的代码。

strone = r"H\te\rl\nl\"o\'"
print(strone)

字符编码

由于计算机是美国人发明的,因此,最早只有 127 个字符被编码到计算机里,也就是大小写英文字母、数字和一些符号,这个编码表被称为 ASCII 编码(范围为 0~127),比如字符 A 的编码是 65,字符 1 的编码是 49。我们知道 1 个字节可以表示的范围是 0~255,所以我们只需要 1 个字节既可以表示出来所有的 ASCII 编码。

strone = "A"
print(ord(strone))  # ASCII 值为 65;用 1 个字节的 2 进制表示为:01000001

strtwo = "1"
print(ord(strtwo))  # ASCII 值为 33;用 1 个字节的 2 进制表示为:00100001

但是要处理中文用 1 个字节显然是不够的,至少需要 2 个字节, 用两个字节表示一个字符(包括英文,数字,可见字符等)的编码,我们称为 UNICODE 编码。我们知道 2 个字节的表示的范围为 0~65535,注意,我们在字符串前面加上 u 来告诉计算机用 UNICODE 编码方式存储字符串。

strone = u"A"
print(ord(strone))  # UNICODE 值为 65;用 2 个字节的 2 进制表示为:00000000 01000001

strtwo = u"牛"
print(ord(strtwo))  # UNICODE 值为 29275;用 2 个字节的 2 进制表示为:01110010 01011011

我们来分析一下上面的例子:汉字“牛”对应的十进制为 29275,显然已经超出了 ASCII 编码的范围,所以用 1 个字节无法表示,我们只能用两个字节的 UNICODE 编码方式,对应的二进制为 01110010 01011011。字母 A 对应的十进制为 65,可以使用 1 个字节的 ASCII 编码方式,对应的二进制为 01000001,当然我们也可以使用 2 个字节的 UNICODE 编码方式,对应的进制为 00000000 01000001。我们来考虑一个问题,如果我们写的字符串文本只有极个别中文,而大部分都是英文,因为有中文的存在,我们无法使用 ASCII 编码方式进行统一编码,只能使用 UNICODE 编码方式,而采用 UNICODE 编码比 ASCII 编码需要多一倍的存储空间,在存储和传输上就十分不划算,如果有一种编码可以智能的对文本中的英文采用 ASCII 编码方式,对中文采用 UNICODE 编码方式那该多好啊,有的,就是 UTF-8 编码。UTF-8 编码把一个 UNICODE 字符根据不同的数字大小编码成 1-6 个字节,比如,如果是常用的英文字符、数字字符、英文符合字符等都被编码成 1 个字节,一般汉字通常是 3 个字节,只有很生僻的字符才会被编码成 4-6 个字节。在 Python 3 中,字符串前面什么都不要加,默认就是采用 UTF-8 编码;如果加上 u 就是 UNICODE 编码。

strone = "you"        # UTF-8 编码,共占用 3 个字节(和 ASCII 编码一样 1 个英文字符 1 个字节)
strtwo = "牛掰"       # UTF-8 编码,共占用 6 个字节(1 个中文字符通常是 3 个字节)
strthree = "you牛掰"  # UTF-8 编码,共占用 9 个字节(1 个英文字符 1 个字节,1 个中文字符通常是 3 个字节)

strfour = u"you"      # UNICODE 编码,共占用 6 个字节(1 个英文字符 2 个字节)
strfive = u"牛掰"     # UNICODE 编码,共占用 4 个字节(1 个中文字符 2 个字节)
strsix = u"you牛掰"   # UNICODE 编码,共占用 10 个字节(1 个英文字符 2 个字节,1 个中文字符 2 个字节)

Python 内置的 len 函数可以计算字符串的长度,但是这个长度是什么意思呢,我们通过查看 len 函数的源码发现,它内部逻辑有个判断:

如果计算的字符串是 UNICODE 编码方式,则返回值是:字符串所占的字节数除以 2。

如果字符串是 UTF-8 编码,对于字符串里面有 ASCII 字符则按字节计算,对于字符串里面的中文字符,则按该中文字符所占的字节数除以编码该中文字符所用的字节数 。

strone = "you"        # UTF-8 编码,共占用 3 个字节(和 ASCII 编码一样,每个英文字符占 1 个字节)
strtwo = "牛掰"       # UTF-8 编码,共占用 6 个字节(每个中文字符通常占 3 个字节)
strthree = "you牛掰"  # UTF-8 编码,共占用 9 个字节(每个英文字符占 1 个字节,每个中文字符通常占 3 个字节)
print(len(strone))    # 3(1 + 1 + 1)
print(len(strtwo))    # 2(3/3 + 3/3)
print(len(strthree))  # 5(1 + 1 + 1 + 3/3 + 3/3)

strfour = u"you"      # UNICODE 编码,共占用 6 个字节(每个英文字符占 2 个字节)
strfive = u"牛掰"     # UNICODE 编码,共占用 4 个字节(每个中文字符占 2 个字节)
strsix = u"you牛掰"   # UNICODE 编码,共占用 10 个字节(每个英文字符占 2 个字节,每个中文字符占 2 个字节)
print(len(strfour))   # 3(2/2 + 2/2 + 2/2)
print(len(strfive))   # 2(2/2 + 2/2)
print(len(strsix))    # 5(2/2 + 2/2 + 2/2 + 2/2 + 2/2)

Python 内置的 encode 函数可以把字符串类型转换为字节类型,encode 的参数决定对字符进行编码时,每个字符使用几个字节。

strone = "you牛掰"
print(type(strone))    # str 类型
print(len(strone))     # 5(1 + 1 + 1 + 3/3 + 3/3)

strtwo = strone.encode("utf8")  # 按 utf8 方式编码(每个 ascii 占 1 个字节,每个中文占 3 个字节)
print(type(strtwo))    # bytes 类型
print(strtwo)          # b'you\xe7\x89\x9b\xe6\x8e\xb0'
print(len(strtwo))     # 9(1 + 1 + 1 + 3 + 3)

strthree = strone.encode("gbk")  # 按 gbk 方式编码(每个 ascii 占 1 个字节,每个中文占 2 个字节)
print(type(strthree))  # bytes 类型
print(strthree)        # b'you\xc5\xa3\xea\xfe'
print(len(strthree))   # 7(1 + 1 + 1 + 2 + 2)

说明:gbk 编码是微软出的对含有中文的字符串进行编码的一种格式,gbk 对 ascii 使用 1 个字节,对中文使用 2 个字节。

注意:我们对字符串使用 encode 编码后的字节是由 encode 的参数决定的,而不是由被编码的字符是什么编码格式决定的, 比如,大家可以把 strone = "you牛掰" 改成 strone = u"you牛掰",做一下验证,结果和上面是一样的。

同样,我们可以使用 decode 函数,把字节类型数据解码成字符串类型。

strone = b'you\xe7\x89\x9b\xe6\x8e\xb0'
print(type(strone))    # bytes 类型
print(len(strone))     # 9(1 + 1 + 1 + 3 + 3)

strtwo = strone.decode("utf8")  # 按 utf8 方式解码(每个 ascii 转为 1 个字符,每 3 个非 ascii 转为 1 个中文)
print(type(strtwo))    # str 类型
print(strtwo)          # you牛掰
print(len(strtwo))     # 5(1 + 1 + 1 + 3/3 + 3/3)

strone = b'you\xc5\xa3\xea\xfe'
strthree = strone.decode("gbk")  # 按 gbk 方式解码(每个 ascii 转为 1 个字符,每 2 个非 ascii 转为 1 个中文)
print(type(strthree))  # str 类型
print(strthree)        # you牛掰
print(len(strthree))   # 5(1 + 1 + 1 + 2/2 + 2/2)

格式化

我们知道 print 函数会把输出的各种类型数据全变成字符串输出到屏幕上, 当其中输出的语句内容有变量的时候,我们需要根据这些变量的类型进行格式化。

name = "如花"
age = 18
print("%s的年龄是%d" % (name, age))

对应的被格式化的变量类型对应的占位符一般如下表。

占位符 被格式化成的类型 被格式化的数据类型
%d 整数 int,float,bool
%f 浮点数 int,float,bool
%s 字符串 所有类型
%x 十六进制整数 int,float,bool

本节重要知识点

切记字符串本身是不可修改的常量。

熟练掌握常用的字符串的操作函数。

弄明白 len 函数的计算方式。

作业

著名公司(某度)对于以下代码,运行一下看下结果,想想为什么?

a = "hello"
b = "HEllo"
c = "hello"
d = b.lower()

print((a is c))
print((a is d))

如果以上内容对您有帮助,请老板用微信扫一下赞赏码,赞赏后加微信号 birdpython 领取免费视频。


登录后评论

user_image
王烽a
2020年8月6日 07:57 回复

True False

a、c的字符串完全相同,而d把b的大写字母变成小写,导致b和d不同


user_image
芳草天
2020年8月3日 19:10 回复

True

False

d将b全转化为小写,这时就会重新分配一个内存去保存d,而不是与a的地址一样。


user_image
聂玉翠
2020年7月31日 12:15 回复

True

False

a与c指向同一地址,a与d地址不同


user_image
15137884849
2020年7月31日 09:01 回复

运行结果:

True False

a、c的字符串完全相同,而d把b的大写字母变成小写,导致b和d不同


user_image
王梅因
2020年7月31日 08:32 回复

True

False

实际上就是判断两个变量指向的对象的内存地址是否相同,运行:

a = "hello"
b = "HEllo"
c = "hello"
d = b.lower()
print (id(a))
print (id(c))
print (id(d))

结果为:

89116224
89116224
88650448

可发现a和c指向的地址一样,所以结果为True;

d把b中所有字母都变为小写并返回,但 这时d和a的地址不同,所以结果为False。


user_image
13781435268
2020年7月31日 07:44 回复

True False


user_image
wuqidi
2020年7月30日 22:45 回复
  • 作业运行结果:
True
False
  • a和c都指向给5的地址,也就是说指向同一个地址,故输出为真。而b和d内容不一样,对应的地址就不同,bd指向的自然不是同一个地址,故输出为假。

user_image
15137867545
2020年7月30日 22:25 回复

True

False


user_image
yyj
2020年7月30日 09:53 回复

a = "hello"

b = "HEllo"

c = "hello"

d = b.lower()

print(d)

print(id(a))

print(id(b))

print(id(c))

print(id(d))

print((a is c))

print((a is d))

hello

1292474520552

1292504355816

1292474520552

1292504355984

True

False

d将b全转化为小写,这时就会重新分配一个内存去保存d;而a和c的值一样,占用一个内存。


user_image
飒蓝
2020年1月25日 06:03 回复

如果你不太确定应该用什么,%s永远起作用,它会把任何数据类型转换为字符串:

另一种格式化字符串的方法是使用字符串的format()方法,它会用传入的参数依次替换字符串内的占位符{0}、{1}……,不过这种方式写起来比%要麻烦得多:

print('%2d-%02d' % (3, 1))

print('%.2f' % 3.1415926)

3-01

3.14


user_image
萃九时凝
2019年12月20日 19:15 回复

打卡

有点懵%


user_image
CharlieJiang
2019年4月14日 23:41 回复

lower 和upper是对字符串大小写全部转化,有没有专门针对某个特殊字符转化的函数除了replace


user_image
钻木取水
2019年3月18日 17:48 回复

在cmd命令下运行 print("\a") 会有提示音,但是pycharm下面没有声音


user_image
nekocode
2019年3月18日 14:04 回复

这作业很有深度啊,对语言了解不深的,根本就弄不懂的


user_image
阮行止
2018年8月23日 17:01 回复

博主编码这块讲的太棒了!