字符串 ====================================== 字符串也是一种数据类型,比如 ``"abc"`` 、 ``"~!@#$"`` 、 ``"我是好人"`` 等用来表示人类语言,在编程过程中我们会经常和字符串打交道,python提供了很多处理字符串的方法,如 ``replace`` 、 ``find`` 、 ``lower`` 等等,后面会一一介绍 编码 --------------------------------------- 在介绍字符串之前,我们先来了解一下编码,大家都知道在计算机中数据都是以二进制保存的,也就是 ``01101111001010`` 这样子,那我们如何保存字符串呢?因为最开始计算机在美国比较流行,美国讲英语,也就26个字母,算上大小写再加上数字标点符号也不够127个,所以美国人把他们用到的字符集用一个字节就可以完全表示了,如B可以用66表示,即 ``01000010``,美国人把这种编码规则叫做 ``ASCII`` 码。 .. note:: 在计算机中一位二进制叫做一位,即1 bit,8位叫一个字节 再后来呢,计算机开始在全世界流行了,但是其它国家并不全使用英文字母语言,比如欧洲很多国家(如德国、法国、瑞典、俄罗斯、波兰等)的字母就和英文字母不一样,其它国家就更不用说了,中国就有几万个汉字,日本也有一万多汉字还有平假名、片假名,所以这些国家也开始制定自己国家语言的字符集,如中国的字符集 ``gbk`` 即 ``GB2312`` 、 ``gbk`` 编码是兼容 ``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编码的代码,还节省了存储空间,节约了传输带宽,具体的编码格式如下所示: .. list-table:: :widths: 15 20 :header-rows: 1 * - 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' 字符串方法 --------------------------------------- 学习完编码这么烧脑的概念后,我们来看点轻松的,怎么在python中处理字符串,首先字符串是一个不可变对象,也就是说不能修改它的内容,但可以修改后再存到另一个变量里 # coding=utf-8是什么鬼? ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 这个注释声明放在python脚本文件第一行,意思是声明该文件的编码方式,也就是说脚本里的字符串是使用什么编码,如下示范,我们使用utf-8编码,然后就可以使用utf-8编码去解码,需要注意的是在python3中,默认使用了utf-8的编码,使用在python3可以不用添加这行声明:: # coding=utf-8 s = '我' print(s.decode('utf-8')) 定义一个unicode字符串 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 在python2.7中,字符串编码默认是跟文件编码走的,但是我们可以显式的指定字符为unicode格式:: # coding=utf-8 s = u'我' print(s) print(s.encode('utf-8')) 计算其中某一个字符的数量 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ :: 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 是否以指定字符串开头/结尾 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ :: 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 转换大小写 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ :: In [39]: s = 'aBcD' In [40]: s.lower() Out[40]: 'abcd' In [41]: s.upper() Out[41]: 'ABCD' 查找字符 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ``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 替换字符 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ replace可以传入两个参数,第一个是要替换内容,第二个是替换内容,替换之后返回替换后的字符串 :: In [53]: s = 'abcdefg' In [54]: s.replace('a', '1') Out[54]: '1bcdefg' 去除字符串头尾的字符串 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ``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' 格式化字符串 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 目前比较常用的有两种方式,第一种是在字符串内容使用 ``%`` 占位,然后在字符串后跟数据 :: 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) 我是好人 拼接字符串 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 在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' Python字符串转义字符 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 在需要在字符中使用特殊字符时,python用反斜杠()转义字符。如下: 转义字符 描述 1. (在行尾时) 续行符 \ 反斜杠符号 #. ' 单引号 #. " 双引号 #. \\a 响铃 #. \\b 退格(Backspace) #. \\e 转义 #. \\000 空 #. \\n 换行 #. \\v 纵向制表符 #. \\t 横向制表符 #. \\r 回车 #. \\f 换页 #. \\oyy 八进制数,yy代表的字符,例如:\o12代表换行 \xyy 十六进制数,yy代表的字符,例如:\x0a代表换行 \other 其它的字符以普通格式输出 其他常用内置函数整理 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ :: 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 参数中