4.6. 字符串

字符串也是一种数据类型,比如 "abc""~!@#$""我是好人" 等用来表示人类语言,在编程过程中我们会经常和字符串打交道,python提供了很多处理字符串的方法,如 replacefindlower 等等,后面会一一介绍

4.6.1. 编码

在介绍字符串之前,我们先来了解一下编码,大家都知道在计算机中数据都是以二进制保存的,也就是 01101111001010 这样子,那我们如何保存字符串呢?因为最开始计算机在美国比较流行,美国讲英语,也就26个字母,算上大小写再加上数字标点符号也不够127个,所以美国人把他们用到的字符集用一个字节就可以完全表示了,如B可以用66表示,即 01000010,美国人把这种编码规则叫做 ASCII 码。

Note

在计算机中一位二进制叫做一位,即1 bit,8位叫一个字节

再后来呢,计算机开始在全世界流行了,但是其它国家并不全使用英文字母语言,比如欧洲很多国家(如德国、法国、瑞典、俄罗斯、波兰等)的字母就和英文字母不一样,其它国家就更不用说了,中国就有几万个汉字,日本也有一万多汉字还有平假名、片假名,所以这些国家也开始制定自己国家语言的字符集,如中国的字符集 gbkGB2312gbk 编码是兼容 ASCII 编码的,但是因为汉字太多了,所以使用了两个字节表示,两个字节16位,也就是最多可以表示65536个字符,足够用了。同时其它国家也制定了类似 gbk 这样的字符集,好吧,这下子乱了套了,比如在中国字符集中用 0b1100111011010010 来表示 ,但翻译成日文字符集(Shift_JIS)却就成了 ホメ ,假如一个字符串中同时包括中文和日文,这叫计算机怎么解码呢?按中文编码解是错的,按日文也是错的,好纠结。。。

In [54]: wo = u'我'

In [55]: wo_gbk = wo.encode('gbk')

In [56]: wo_gbk
Out[56]: '\xce\xd2'

In [57]: print(wo_gbk.decode('Shift_JIS'))
ホメ

In [58]:

于是乎,编码这个问题成了计算机的一个大问题,为了解决这个问题,ISO制定了一个宏大的计算,把全世界的字符都包含进来,全名为 unicode 也叫 统一码万国码 ,unicode一般占用2个字节,下面我们显示一下在python里定义unicode字符

In [1]: ustr = u"我是好人"

In [2]: ustr
Out[2]: u'\u6211\u662f\u597d\u4eba'

In [3]: ustr2 = u'\u6211\u662f\u597d\u4eba'

In [4]: ustr2
Out[4]: u'\u6211\u662f\u597d\u4eba'

In [5]: print(ustr2)
我是好人

好,现在世界的字符编码统一了,但又有问题了,欧美那些国家因为是使用字母,以前1个字节就搞定了,现在为了照顾其他国家,竟然要多用1个字节,这要浪费多少硬盘、内存和网络带宽啊,不公平,抵制~!!!于是乎,又出现了 UTF-8 编码,这个字符集的特点是兼容 ASCII ,即 ASCII 是它的一个字集,它把原先的 ASCII 字符仍编码为1个字节,另外一些常用的其它国家字符编码为2个字节,一些生僻字编码为3-6个字节,于是即照了欧美众国的程序员情绪、兼容了之前用ASCII编码的代码,还节省了存储空间,节约了传输带宽,具体的编码格式如下所示:

Unicode编码(十六进制) UTF-8 字节流(二进制)
000000-00007F 0xxxxxxx
000080-0007FF 110xxxxx 10xxxxxx
000800-00FFFF 1110xxxx 10xxxxxx 10xxxxxx
010000-10FFFF 11110xxx10xxxxxx10xxxxxx10xxxxxx

也就是说UTF-8编码的字符没有固定长度,是变长的,来我们看一下unicode和utf-8的转换:

In [11]: unicode_str = u"我"

In [12]: utf8_str = unicode_str.encode('utf-8') #  使用encode(翻译成中文是编码)方法、utf-8来编码unicode字符

In [13]: utf8_str
Out[13]: '\xe6\x88\x91'

In [14]: utf8_str.decode('utf-8') #  使用decode(翻译成中文是解)方法、utf-8来解码unicode字符
Out[14]: u'\u6211'

In [15]:

大家试一下,体会一下,讲到这里,大家是不是有点感觉了?其它unicode和utf-8还有很多非常细的知识点,不过我们掌握这些基础的一般就够用了,下面我们来试一下unicode和其它编码的转换:

In [6]: unicode_wo = u"我"

In [7]: gbk_wo = unicode_wo.encode('gbk')

In [8]: gbk_wo
Out[8]: '\xce\xd2'

In [9]: Shift_JIS_wo = unicode_wo.encode('Shift_JIS')

In [10]: Shift_JIS_wo
Out[10]: '\x89\xe4'

4.6.2. 字符串方法

学习完编码这么烧脑的概念后,我们来看点轻松的,怎么在python中处理字符串,首先字符串是一个不可变对象,也就是说不能修改它的内容,但可以修改后再存到另一个变量里

4.6.2.1. # coding=utf-8是什么鬼?

这个注释声明放在python脚本文件第一行,意思是声明该文件的编码方式,也就是说脚本里的字符串是使用什么编码,如下示范,我们使用utf-8编码,然后就可以使用utf-8编码去解码,需要注意的是在python3中,默认使用了utf-8的编码,使用在python3可以不用添加这行声明:

# coding=utf-8

s = '我'
print(s.decode('utf-8'))

4.6.2.2. 定义一个unicode字符串

在python2.7中,字符串编码默认是跟文件编码走的,但是我们可以显式的指定字符为unicode格式:

# coding=utf-8

s = u'我'

print(s)

print(s.encode('utf-8'))

4.6.2.3. 计算其中某一个字符的数量

In [21]: s = 'abbcccdddd'

In [22]: s.count('a')
Out[22]: 1

In [23]: s.count('b')
Out[23]: 2

In [24]: s.count('d')
Out[24]: 4

4.6.2.4. 是否以指定字符串开头/结尾

In [25]: s = 'abbcccdddd'

In [26]: s.startswith('ab')
Out[26]: True

In [27]: s.startswith('abc')
Out[27]: False

In [28]: s.endswith('ddd')
Out[28]: True

In [29]: s.endswith('ddde')
Out[29]: False

4.6.2.5. 转换大小写

In [39]: s = 'aBcD'

In [40]: s.lower()
Out[40]: 'abcd'

In [41]: s.upper()
Out[41]: 'ABCD'

4.6.2.6. 查找字符

find 方法可以从字符串左边开始查找字符,找到后返回字符位置,否则返回-1, rfind 可以从右边开始查找

In [48]: s = 'abccba'

In [49]: s.find('a')
Out[49]: 0

In [50]: s.find('b')
Out[50]: 1

In [51]: s.find('d')
Out[51]: -1

In [52]: s.rfind('a')
Out[52]: 5

4.6.2.7. 替换字符

replace可以传入两个参数,第一个是要替换内容,第二个是替换内容,替换之后返回替换后的字符串

In [53]: s = 'abcdefg'

In [54]: s.replace('a', '1')
Out[54]: '1bcdefg'

4.6.2.8. 去除字符串头尾的字符串

strip 这个方法是非常有用的,可以去除字符串头尾指定的字符串,默认是空格、换行符、制表符等,rstrip 是只去除右边的, lstrip 是只去除左边的,除了默认的字符串,也可以指定值:

In [59]: s = '\n\t abc  \n\t'

In [60]: s.strip()
Out[60]: 'abc'

In [61]: s.lstrip()
Out[61]: 'abc  \n\t'

In [62]: s.rstrip()
Out[62]: '\n\t abc'

In [65]: s.strip('\t')
Out[65]: '\n\t abc  \n'

# 注意下面这个例子
In [66]: s.strip('\n')
Out[66]: '\t abc  \n\t'

4.6.2.9. 格式化字符串

目前比较常用的有两种方式,第一种是在字符串内容使用 % 占位,然后在字符串后跟数据

In [70]: s = '我是%s人' % '好'

In [71]: print(s)
我是好人

In [72]: s1 = '我是%s%s' % ('我', '吗')

In [73]: print(s1)
我是我人吗

第二种是使用字符串的format函数:

In [74]: s = '我是{what}人'.format(what='好')

In [75]: print(s)
我是好人

4.6.2.10. 拼接字符串

在python中可以直接使用 + 来拼接字符串,但是两边的python字符串编码要兼容

In [79]: s1 = 'abc'

In [80]: s2 = '123'

In [81]: s1 + s2
Out[81]: 'abc123'

除此之外,还有一个 join 方法去把字符/字符串列表(或者可迭代对象均可)拼接起来:

In [83]: s1 = ['ab', 'cd', 'ef']

In [84]: ''.join(s1)
Out[84]: 'abcdef'

In [85]: '.'.join(s1)
Out[85]: 'ab.cd.ef'

In [86]: s2 = 'abcdefg'

In [88]: '.'.join(s2)
Out[88]: 'a.b.c.d.e.f.g'

4.6.2.11. Python字符串转义字符

在需要在字符中使用特殊字符时,python用反斜杠()转义字符。如下:

转义字符 描述

  1. (在行尾时) 续行符 反斜杠符号
  2. ‘ 单引号
  3. ” 双引号
  4. \a 响铃
  5. \b 退格(Backspace)
  6. \e 转义
  7. \000 空
  8. \n 换行
  9. \v 纵向制表符
  10. \t 横向制表符
  11. \r 回车
  12. \f 换页
  13. \oyy 八进制数,yy代表的字符,例如:o12代表换行 xyy 十六进制数,yy代表的字符,例如:x0a代表换行 other 其它的字符以普通格式输出

4.6.2.12. 其他常用内置函数整理

string.capitalize() #把字符串的第一个字符大写

string.center(width) #返回内容是原字符串居中,并使用空格填充至长度为 width 的新字符串

string.count(str, beg=0, end=len(string)) #返回 str 在 string 里面出现的次数,如果 beg 或者 end 指定则返回指定范围内 str 出现的次数

string.expandtabs(tabsize=8) #把字符串 string 中的 tab 符号转为空格,tab 符号默认的空格数是 8

string.find(str, beg=0, end=len(string)) #检测 str 是否包含在 string 中,如果 beg 和 end 指定范围,则检查是否包含在指定范围内,如果是返回开始的索引值,否则返回-1

string.index(str, beg=0, end=len(string)) #跟find()方法一样,只不过如果str不在 string中会报一个异常

string.isalnum() #如果 string 至少有一个字符并且所有字符都是字母或数字则返回 True,否则返回 False

string.isalpha() #如果 string 至少有一个字符并且所有字符都是字母则返回 True,否则返回 False

string.isdecimal() #如果 string 只包含十进制数字则返回 True 否则返回 False.

string.isdigit() #如果 string 只包含数字则返回 True 否则返回 False

string.islower() #如果 string 中包含至少一个区分大小写的字符,并且所有这些(区分大小写的)字符都是小写,则返回 True,否则返回 False

string.isnumeric() #如果 string 中只包含数字字符,则返回 True,否则返回 False

string.isspace() #如果 string 中只包含空格,则返回 True,否则返回 False

string.istitle() #如果 string 是标题化的(见 title())则返回 True,否则返回 False

string.isupper() #如果 string 中包含至少一个区分大小写的字符,并且所有这些(区分大小写的)字符都是大写,则返回 True,否则返回 False

string.ljust(width) #返回一个原字符串左对齐,并使用空格填充至长度 width 的新字符串

string.maketrans(intab, outtab]) maketrans() #方法用于创建字符映射的转换表,对于接受两个参数的最简单的调用方式,第一个参数是字符串,表示需要转换的字符,第二个参数也是字符串表示转换的目标。

max(str) #返回字符串 str 中最大的字母

min(str) #返回字符串 str 中最小的字母

string.partition(str) #有点像 find()和 split()的结合体,从 str 出现的第一个位置起,把 字 符 串 string 分成一个3元素的元组(string_pre_str,str,string_post_str),如果 string 中不包含str 则 string_pre_str == string

string.replace(str1, str2, num=string.count(str1)) #把 string 中的 str1 替换成 str2,如果 num 指定,则替换不超过 num 次

string.rfind(str, beg=0,end=len(string) ) #类似于 find()函数,不过是从右边开始查找

string.rindex( str, beg=0,end=len(string)) #类似于 index(),不过是从右边开始

string.rjust(width) #返回一个原字符串右对齐,并使用空格填充至长度 width 的新字符串

string.rpartition(str) #类似于partition()函数,不过是从右边开始查找

string.rstrip() #删除 string 字符串末尾的空格

string.split(str="", num=string.count(str)) #以 str 为分隔符切片 string,如果 num有指定值,则仅分隔 num 个子字符串

string.splitlines(num=string.count('')) #按照行分隔,返回一个包含各行作为元素的列表,如果 num 指定则仅切片 num 个行

string.startswith(obj, beg=0,end=len(string)) #检查字符串是否是以 obj 开头,是则返回 True,否则返回 False。如果beg 和 end 指定值,则在指定范围内检查.

string.strip([obj]) #在 string 上执行 lstrip()和 rstrip()

string.swapcase() #翻转 string 中的大小写

string.title() #返回"标题化"的 string,就是说所有单词都是以大写开始,其余字母均为小写(见 istitle() 即改为驼峰展示)

string.translate(str, del="") 根据 str 给出的表(包含 256 个字符)转换 string 的字符,要过滤掉的字符放到 del 参数中