7 字符串

在 Python 开发过程中,经常需要对字符串进行一些特殊处理,比如拼接字符串、截取字符串、格式化字符串等,这些操作无需开发者自己设计实现,只需调用相应的字符串方法即可。

创建字符串

字符串是 Python 中最常用的数据类型。我们可以使用单引号(')或双引号(")来创建字符串。

Python 中三引号可以将复杂的字符串进行赋值。 Python 三引号允许一个字符串跨多行,字符串中可以包含换行符、制表符以及其他特殊字符。 三引号的语法是一对连续的单引号(''')或者双引号(""")(通常都是成对的用)。

Python 不支持单字符类型,单字符在 Python 中也是作为一个字符串使用。

字符串编码

最早的字符串编码是美国标准信息交换码ASCII,仅对10个数字、26个大写英文字母、26个小写英文字母及一些其他符号进行了编码。ASCII码采用1个字节来对字符进行编码,最多只能表示256个符号。

随着信息技术的发展和信息交换的需要,各国的文字都需要进行编码,不同的应用领域和场合对字符串编码的要求也略有不同,于是又分别设计了多种不同的编码格式,常见的主要有UTF-8、UTF-16、UTF-32、GB2312、GBK、CP936等。

GB2312是我国制定的中文编码,使用1个字节表示英语,2个字节表示中文;GBK是GB2312的扩充,而CP936是微软在GBK基础上开发的编码方式。GB2312、GBK和CP936都是使用2个字节表示中文。

UTF-8国际通过的编码格式,它包含了全世界所有国家需要用到的字符,对全世界所有国家需要用到的字符进行了编码,以1个字节表示英语字符(兼容ASCII),以3个字节表示常见汉字,还有些语言的符号使用2个字节(例如俄语和希腊语符号)或者4个字节。

不同编码格式之间相差很大,采用不同的编码格式意味着不同的表示和存储形式,把同一字符存入文件时,写入的内容可能会不同,在试图理解其内容时必须了解编码规则并进行正确的解码。如果解码方法不正确就无法还原信息,从这个角度来讲,字符串编码也具有加密的效果。

UTF-8字符串

Python 3.x完全支持中文字符,默认使用UTF-8编码格式,无论是一个数字、英文字母,还是一个汉字,在统计字符串长度时都按一个字符对待和处理。

定义Unicode字符串

Python 中定义一个 Unicode 字符串和定义一个普通字符串一样简单:

u'Hello World !'

引号前小写的"u"表示这里创建的是一个 Unicode 字符串。如果你想加入一个特殊字符,可以使用 Python 的 Unicode-Escape 编码。如下例所示:

u'Hello\u0020World !'

其他编码转换方法

encode()

encode的作用是将unicode编码转换成其他编码的字符串,如str2.encode('gb2312'),表示将unicode编码的字符串str2转换成gb2312编码。

decode()

decode的作用是将其他编码的字符串转换成unicode编码,如str1.decode('gb2312'),表示将gb2312编码的字符串str1转换成unicode编码。

转义字符

转义字符描述
\(在行尾时)续行符
\\反斜杠符号
\'单引号
\"双引号
\a响铃
\b退格(Backspace)
\e转义
\000
\n换行
\v纵向制表符
\t横向制表符
\r回车
\f换页
\oyy八进制数,yy代表的字符,例如:\o12代表换行
\xyy十六进制数,yy代表的字符,例如:\x0a代表换行
\other其它的字符以普通格式输出

字符串格式化

1605112834439

常用格式字符

格式字符说明
%s字符串 (采用str()的显示)
%r字符串 (采用repr()的显示)
%c单个字符
%d十进制整数
%i十进制整数
%o八进制整数
%x十六进制整数
%e指数 (基底写为e)
%E指数 (基底写为E)
%f、%F浮点数
%g指数(e)或浮点数 (根据显示长度)
%G指数(E)或浮点数 (根据显示长度)
%%一个字符%

格式化操作符辅助指令:

符号功能
*定义宽度或者小数点精度
-用做左对齐
+在正数前面显示加号( + )
<sp>在正数前面显示空格
#在八进制数前面显示零('0'),在十六进制前面显示'0x'或者'0X'(取决于用的是'x'还是'X')
0显示的数字前面填充'0'而不是默认的空格
%%'%%'输出一个单一的'%'
(var)映射变量(字典参数)
m.n.m 是显示的最小总宽度,n 是小数点后的位数(如果可用的话)

例如:

>>> x = 1235
>>> "%o" % x
"2323"
>>> "%x" % x
"4d3"
>>> "%e" % x
"1.235000e+03"
>>> "%s" % 65
"65"
>>> "%s" % 65333
"65333"
>>> "%d" % "555"
TypeError: %d format: a number is required, not str
>>> '%s'%[1, 2, 3]        #直接把对象转换成字符串
'[1, 2, 3]'

format() 方法

format() 方法的语法格式如下:

str.format(args)
  • str 用于指定字符串的显示样式;args 用于指定要进行格式转换的项,如果有多项,之间有逗号进行分割。

难点在于搞清楚str显示样式的书写格式,创建显示模板时,需要使用{}和:里指定占位符,完整格式如下:

{ [index][ : [ [fill] align] [sign] [#] [width] [.precision] [type] ] }
  • index:指定:后边设置的格式要作用到 args 中第几个数据,数据的索引值从 0 开始。如果省略此选项,则会根据 args 中数据的先后顺序自动分配。
  • fill:指定空白处填充的字符。注意,当填充字符为逗号(,)且作用于整数或浮点数时,该整数(或浮点数)会以逗号分隔的形式输出。
  • align:指定数据的对齐方式,<(左对齐),>(右对齐),=(数据右对齐,同时将符号放置在填充内容的最左侧), ^(居中)
  • sign:指定有无符号数, +(正数前加正号,负数前加负号), -(正数前不加正号,负数前加负号),(空格)正数前加空格,负数前加负号, #(对于二进制数、八进制数和十六进制数,使用此参数,各进制数前会分别显示 0b、0o、0x前缀;)
  • width:指定输出数据时所占的宽度
  • .precision:指定保留的小数位数
  • type:指定输出数据的具体类型

1605113072003

>>> print("The number {0:,} in hex is: {0:#x}, the number {1} in oct is {1:#o}".format(5555,55))
The number 5,555 in hex is: 0x15b3, the number 55 in oct is 0o67

>>> print("The number {1:,} in hex is: {1:#x}, the number {0} in oct is {0:o}".format(5555,55))
The number 55 in hex is: 0x37, the number 5555 in oct is 12663

>>> print("my name is {name}, my age is {age}, and my QQ is {qq}".format(name="Dong Fuguo",age=40,qq="30646****"))
my name is Dong Fuguo, my age is 40, and my QQ is 30646****

>>> position = (5, 8, 13)
>>> print("X:{0[0]};Y:{0[1]};Z:{0[2]}".format(position))
X:5;Y:8;Z:13

>>> '{0:<8d},{0:^8d},{0:>8d}'.format(65) #设置对齐方式
'65      ,   65   ,      65

>>> '{0:+<8d},{0:-^8d},{0:=>8d}'.format(65)
'65++++++,---65---,======65'

Formatted String Literals

从Python 3.6.x开始支持一种新的字符串格式化方式,官方叫做Formatted String Literals,在字符串前加字母f,含义与字符串对象format()方法类似。

>>> width = 8
>>> height = 6
>>> print(f'Rectangle of {width}*{height}\nArea:{width*height}')
Rectangle of 8*6
Area:48
>>> print(f'{width*height=}')           # Python 3.8开始支持
width*height=48

字符串运算符

操作符描述实例
+字符串连接>>>a + b 'HelloPython'
*重复输出字符串>>>a * 2 'HelloHello'
[]通过索引获取字符串中字符>>>a[1] 'e'
[ : ]截取字符串中的一部分>>>a[1:4] 'ell'
in成员运算符 - 如果字符串中包含给定的字符返回 True>>>"H" in a True
not in成员运算符 - 如果字符串中不包含给定的字符返回 True>>>"M" not in a True
r/R原始字符串 - 原始字符串:所有的字符串都是直接按照字面的意思来使用,没有转义特殊或不能打印的字符。 原始字符串除在字符串的第一个引号前加上字母"r"(可以大小写)以外,与普通字符串有着几乎完全相同的语法。>>>print r'\n' \n >>> print R'\n' \n
%格式字符串 

成员判断 in

>>> "a" in "abcde"     #测试一个字符中是否存在于另一个字符串中
True
>>> 'ab' in 'abcde'
True
>>> 'ac' in 'abcde'    #关键字in左边的字符串作为一个整体对待
False
>>> "j" in "abcde"
False

重复输出字符串 *

Python字符串支持与整数的乘法运算,表示序列重复,也就是字符串内容的重复,得到新字符串。

>>> 'abcd' * 3
'abcdabcdabcd'

字符串常用方法

查找与计数 find()、rfind()、index()、rindex()、count()

find()和rfind方法分别用来查找一个字符串在另一个字符串指定范围(默认是整个字符串)中首次和最后一次出现的位置,如果不存在则返回-1;

index()和rindex()方法用来返回一个字符串在另一个字符串指定范围中首次和最后一次出现的位置,如果不存在则抛出异常;

count()方法用来返回一个字符串在当前字符串中出现的次数。

分割 split()、rsplit()、partition()、rpartition()

split()和rsplit()方法分别用来以指定字符为分隔符,这些子串会被保存到列表中(不包含分隔符),把当前字符串从左往右或从右往左分隔成多个字符串,并返回包含分隔结果的列表;

str.split(sep,maxsplit)
  • sep:用于指定分隔符,可以包含多个字符。此参数默认为 None,表示所有空字符,包括空格、换行符“\n”、制表符“\t”等。 maxsplit:可选参数,用于指定分割的次数。
  • partition()和rpartition()用来以指定字符串为分隔符将原字符串分隔为3部分,即分隔符前的字符串、分隔符字符串、分隔符后的字符串,如果指定的分隔符不在原字符串中,则返回原字符串和两个空字符串。

对于split()和rsplit()方法,如果不指定分隔符,则字符串中的任何空白符号(空格、换行符、制表符等)都将被认为是分隔符,并删除切分结果中的空字符串。

然而,明确传递参数指定split()使用的分隔符时,情况是不一样的,会保留切分得到的空字符串。

split()和rsplit()方法还允许指定最大分割次数。

>>> s = '\n\nhello\t\t world \n\n\n My name is Dong   '
>>> s.split(None, 1)        #不指定分隔符,使用空白字符作为分隔符
['hello', 'world \n\n\n My name is Dong   ']
>>> s.rsplit(None, 1)
['\n\nhello\t\t world \n\n\n My name is', 'Dong']
>>> s.split(None, 2)
['hello', 'world', 'My name is Dong   ']
>>> s.rsplit(None, 2)
['\n\nhello\t\t world \n\n\n My name', 'is', 'Dong']
>>> s.split(maxsplit=6)
['hello', 'world', 'My', 'name', 'is', 'Dong']
>>> s.split(maxsplit=100)   #最大分隔次数大于可分隔次数时无效
['hello', 'world', 'My', 'name', 'is', 'Dong']

连接 join()

字符串连接join() ,它是 split() 方法的逆方法,用来将列表(或元组)中包含的多个字符串连接成一个字符串。

>>> li = ["apple", "peach", "banana", "pear"]
>>> ','.join(li)
'apple,peach,banana,pear'
>>> '.'.join(li)
'apple.peach.banana.pear'
>>> '::'.join(li)
'apple::peach::banana::pear'

不推荐使用+运算符连接字符串,优先使用join()方法。

大小写转换 lower()、upper()、capitalize()、title()、swapcase()

>>> s = "What is Your Name?"
>>> s.lower()                   #返回小写字符串
'what is your name?'
>>> s.upper()                   #返回大写字符串
'WHAT IS YOUR NAME?'
>>> s.capitalize()              #字符串首字符大写
'What is your name?'
>>> s.title()                   #每个单词的首字母大写
'What Is Your Name?'
>>> s.swapcase()                #大小写互换
'wHAT IS yOUR nAME?'

替换 replace()

查找替换replace(),类似于Word中的“全部替换”功能。

>>> words = ('测试', '非法', '暴力', '话')
>>> text = '这句话里含有非法内容'
>>> for word in words:
    if word in text:
        text = text.replace(word, '***')		
>>> text
'这句***里含有***内容'

字符映射表 maketrans()、translate()

字符串对象的maketrans()方法用来生成字符映射表,而translate()方法用来根据映射表中定义的对应关系转换字符串并替换其中的字符,使用这两个方法的组合可以同时处理多个字符。

str.maketrans(intab, outtab)
>>> table = ''.maketrans('0123456789', '零一二三四伍陆柒捌玖')
>>> '2018年12月31日'.translate(table)
'二零一捌年一二月三一日'

删除字符 strip()、rstrip()、lstrip()

>>> s = " abc  "
>>> s.strip()                             #删除空白字符
'abc'
>>> '\n\nhello world   \n\n'.strip()      #删除空白字符
'hello world'
>>> "aaaassddf".strip("a")                #删除指定字符
'ssddf'
>>> "aaaassddf".strip("af")
'ssdd'
>>> "aaaassddfaaa".rstrip("a")            #删除字符串右端指定字符
'aaaassddf'
>>> "aaaassddfaaa".lstrip("a")            #删除字符串左端指定字符
'ssddfaaa'

这三个方法的参数指定的字符串并不作为一个整体对待,而是在原字符串的两侧、右侧、左侧删除参数字符串中包含的所有字符,一层一层地从外往里扒。

>>> 'aabbccddeeeffg'.strip('af')  #字母f不在字符串两侧,所以不删除
'bbccddeeeffg'
>>> 'aabbccddeeeffg'.strip('gaf')
'bbccddeee'
>>> 'aabbccddeeeffg'.strip('gaef')
'bbccdd'
>>> 'aabbccddeeeffg'.strip('gbaef')
'ccdd'
>>> 'aabbccddeeeffg'.strip('gbaefcd')
''
>>> text = '''姓名:张三
年龄:39
性别男
职业  学生
籍贯:  地球'''
>>> infomation = text.split('\n')
>>> infomation
['姓名:张三', '年龄:39', '性别男', '职业  学生', '籍贯:  地球']
>>> for item in infomation:
    print(item[:2], item[2:].strip(': '), sep=':')
	
姓名:张三
年龄:39
性别:男
职业:学生
籍贯:地球

对齐 center()、ljust()、rjust()

center()、ljust()、rjust(),返回指定宽度的新字符串,原字符串居中、左对齐或右对齐出现在新字符串中,如果指定宽度大于字符串长度,则使用指定的字符(默认为空格)进行填充。

>>> 'Hello world!'.center(20)        #居中对齐,以空格进行填充
'    Hello world!    '
>>> 'Hello world!'.center(20, '=')   #居中对齐,以字符=进行填充
'====Hello world!===='
>>> 'Hello world!'.ljust(20, '=')    #左对齐
'Hello world!========'
>>> 'Hello world!'.rjust(20, '=')    #右对齐
'========Hello world!'

判断 startswith(t)、endswith(t)

s.startswith(t)、s.endswith(t),判断字符串是否以指定字符串开始或结束。

>>> s = 'Beautiful is better than ugly.'
>>> s.startswith('Be')           #检测整个字符串
True
>>> s.startswith('Be', 5)        #指定检测范围起始位置
False
>>> s.startswith('Be', 0, 5)     #指定检测范围起始和结束位置
True
>>> import os
>>> [filename for filename in os.listdir(r'c:\\')
     if filename.endswith(('.bmp','.jpg','.gif'))]

判断 isalnum()、isalpha()、isdigit()、isdecimal()、isnumeric()、isspace()、isupper()、islower()

isalnum()、isalpha()、isdigit()、isdecimal()、isnumeric()、isspace()、isupper()、islower(),用来测试字符串是否为数字或字母、是否为字母、是否为数字字符、是否为空白字符、是否为大写字母以及是否为小写字母。

>>> '1234abcd'.isalnum()
True
>>> '1234abcd'.isalpha()         #全部为英文字母时返回True
False
>>> '1234abcd'.isdigit()         #全部为数字时返回True
False
>>> 'abcd'.isalpha()
True
>>> '1234.0'.isdigit()
False

执行 eval()

>>> eval("3+4")                             #计算表达式的值
7
>>> a = 3
>>> b = 5
>>> eval('a+b')                             #要求变量a和b已存在
8
>>> import math
>>> eval('math.sqrt(3)')
1.7320508075688772
>>> eval('aa')                              #当前上下文中不存在对象aa
NameError: name 'aa' is not defined
>>> eval('*'.join(map(str, range(1, 6))))   #5的阶乘
120

eval()函数是非常危险的。

其他

除了字符串对象提供的方法以外,很多Python内置函数也可以对字符串进行操作,例如:

>>> x = 'Hello world.'
>>> max(x), min(x), len(x)
('w', ' ', 12)
>>> max(['abc', 'ABD'], key=str.upper) #忽略大小写
'ABD'
>>> sorted(x)
[' ', '.', 'H', 'd', 'e', 'l', 'l', 'l', 'o', 'o', 'r', 'w']
>>> list(zip(x,x))                     #zip()也可以作用于字符串
[('H', 'H'), ('e', 'e'), ('l', 'l'), ('l', 'l'), ('o', 'o'), (' ', ' '), ('w', 'w'), ('o', 'o'), ('r', 'r'), ('l', 'l'), ('d', 'd'), ('.', '.')]
>>> eval('[1, 2, 3, 4]')		        #字符串求值
[1, 2, 3, 4]

切片也适用于字符串,但仅限于读取其中的元素,不支持字符串修改。

>>> 'Explicit is better than implicit.'[:8]
'Explicit'
>>> 'Explicit is better than implicit.'[9:23]
'is better than'

Pytho标准库zlib中提供的compress()和decompress()函数可以用于字节串的压缩和解压缩。

Python标准库string中定义数字字符、标点符号、英文字母、大写字母、小写字母等常量。

>>> import string
>>> string.digits
'0123456789'
>>> string.punctuation
'!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~'
>>> string.ascii_letters
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
>>> string.ascii_lowercase
'abcdefghijklmnopqrstuvwxyz'
>>> string.ascii_uppercase
'ABCDEFGHIJKLMNOPQRSTUVWXYZ'

字符串内建函数表

方法描述
string.capitalize()把字符串的第一个字符大写
string.center(width)返回一个原字符串居中,并使用空格填充至长度 width 的新字符串
string.count(str, beg=0, end=len(string))返回 str 在 string 里面出现的次数,如果 beg 或者 end 指定则返回指定范围内 str 出现的次数
string.decode(encoding='UTF-8', errors='strict')以 encoding 指定的编码格式解码 string,如果出错默认报一个 ValueError 的 异 常 , 除非 errors 指 定 的 是 'ignore' 或 者'replace'
string.encode(encoding='UTF-8', errors='strict')以 encoding 指定的编码格式编码 string,如果出错默认报一个ValueError 的异常,除非 errors 指定的是'ignore'或者'replace'
string.endswith(obj, beg=0, end=len(string))检查字符串是否以 obj 结束,如果beg 或者 end 指定则检查指定的范围内是否以 obj 结束,如果是,返回 True,否则返回 False.
string.expandtabs(tabsize=8)把字符串 string 中的 tab 符号转为空格,tab 符号默认的空格数是 8。
string.find(str, beg=0, end=len(string))检测 str 是否包含在 string 中,如果 beg 和 end 指定范围,则检查是否包含在指定范围内,如果是返回开始的索引值,否则返回-1
string.format()格式化字符串
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.join(seq)以 string 作为分隔符,将 seq 中所有的元素(的字符串表示)合并为一个新的字符串
string.ljust(width)返回一个原字符串左对齐,并使用空格填充至长度 width 的新字符串
string.lower()转换 string 中所有大写字符为小写.
string.lstrip()截掉 string 左边的空格
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() 函数,返回字符串最后一次出现的位置,如果没有匹配项则返回 -1。
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([keepends])按照行('\r', '\r\n', \n')分隔,返回一个包含各行作为元素的列表,如果参数 keepends 为 False,不包含换行符,如果为 True,则保留换行符。
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 参数中
string.upper()转换 string 中的小写字母为大写
string.zfill(width)返回长度为 width 的字符串,原字符串 string 右对齐,前面填充0

可变字符串

在Python中,字符串属于不可变对象,不支持原地修改,如果需要修改其中的值,只能重新创建一个新的字符串对象。然而,如果确实需要一个支持原地修改的数据对象,可以使用io.StringIO对象或array模块。

StringIO顾名思义就是在内存中读写str。要把str写入StringIO,我们需要先创建一个StringIO,然后,像文件一样写入即可。