字符串

阅读 66

字符串是一种表示文本的数据类型,叫 str,是由零个或多个字符组成的有限序列。Python 对字符串操作提供累多种便捷的工具。

形式

python 中一般用单引号或者双引号表示,其结果是一样的。

>>> a = 'abcd'
>>> a
'abcd'
>>> b = "abcd"
>>> b
'abcd'
>>> a == b
True

通常,如果字符串中有双引号,就用单引号表示;如果有单引号就用双引号表示。

>>> a = "this's Python"
>>> a
"this's Python"
>>> b = 'I say, "Hello Python"'
>>> b
'I say, "Hello Python"'

但是如果遇到同时包含单引号和双引号的字符串,如果表示呢?处理的方法有很多种,可以使用转义字符,三重引号。

转义字符使用斜线\ 加字符表示,比如 \' 表示单引号,\" 表示双引号。用来处理字符串中的一些特殊情况,比如字符不能直接使用(\'\")、字符没有直接定义(\n 表示换行符,\t 表示垂直制表符)等。暂时先记住 \n 表示换行符,意思是一行字符串结束了,开始新的一行。

>>> a = "this work, ' \""
>>> a
'this work, \' "'
>>> b = 'this work, \' "'
>>> b
'this work, \' "'
>>> a == b
True

三重引号,顾名思义,就是形如'''....''',和"""...."""的字符串表示方法。也可以表示多行字符串,三重引号会自动添加换行符,如果想要不添加则需要在相应位置添加 \ 字符。注意变量 c 和 d 中的换行符。

>>> a = """this work, ' " """
>>> a
'this work, \' " '
>>> b = '''this work, ' " '''
>>> b
'this work, \' " '
>>> c = '''this work,
... ' " '''
>>> c
'this work,\n\' " '
>>> d = '''this work,\
... ' " '''
>>> d
'this work,\' " '

另外一种表示方法是原始字符串。是在单引号或者双引号前加上 r ,则字符串的内容不会被转义。如下面的变量 b ,在输出的时候,斜杠变成两个了,这表示 \n 并不是一个字符了,而是 \n\\\ 转义字符。

>>> a = 'a\nb'
>>> a
'a\nb'
>>> b = r'a\nb'
>>> b
'a\\nb'

索引

字符串是字符组成的串,可以每个位置的字符可以根据位置索引来确定的。方法是在字符串变量的后面加上中括号,中括号的中间是索引,例如 a[1]。注意:位置索引是从 0 开始的,比如字符串 hello 的长度是5,那么它的索引就是 0、1、2、3、4。

>>> a = 'hello python'
>>> a[0]
'h'
>>> a[1]
'e'
>>> a[2]
'l'
>>> a[3]
'l'
>>> a[10]
'o'
>>> a[11]
'n'

如果索引值超过字符的长度会引发所以错误IndexError。Python 提供了 len 函数来确认字符串的长度。

>>> a[12]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: string index out of range
>>> len(a)
12

也可以用负值来表示索引,负索引表示从后向前数,从 -1 开始。同样,如果超出边界,也会引发索引错误。

>>> a = 'hello'
>>> a[-1]
'o'
>>> a[-2]
'l'
>>> a[-3]
'l'
>>> a[-4]
'e'
>>> a[-5]
'h'
>>> a[-6]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: string index out of range

切片

字符串切片,也叫子字符串,表示字符串的一部分。形式和字符串索引相似,一个数字能够确定位置,表示索引;两个数字确定范围,表示切片。a[0:5] ,中括号里的第一个参数表示起始位置,第二个参数表示结束位置(结束位置不包含在内)。

>>> a = 'hello Python'
>>> a[0:5]
'hello'
>>> a[6:12]
'Python'

参数可以为空,默认是0,和字符串的长度。

>>> a = 'hello Python'
>>> a[:5]
'hello'
>>> a[6:]
'Python'
>>> a[:]
'hello Python'

同样切片参数也可以使用负值。位置同样也是从最后一个字符开始索引表示 -1,每向前一个字符索引减一。

>>> a = 'hello Python'
>>> a[:-7]
'hello'
>>> a[-6:]
'Python'

在切片中,不存在索引越界的行为,默认使用边界值。

>>> a = 'hello Python'
>>> a[100:200]
''

这都是连续的切片。切片可以设置第三个参数,表示从第一个参数的索引位置开始,每隔第三个参数的位置选一个字符,直到第二个参数位置结束。比如 a[1:10:2] 表示从索引为1的位置开始,每隔两个选一个,分别是 3、5、7、9 ,直到 10 结束。

>>> a = 'hello Python'
>>> a[1:10:2]
'el yh'

字符串拼接

字符串拼接十分简单。直接相加即可,特别的,对于字符串字面值可以不写加号。注意,变量和字符串字面值不能省略加号。

>>> a = 'hello'
>>> b = 'world'
>>> a + b
'helloworld'
>>> 'hello' 'world'
'helloworld'
>>> a + 'world'
'helloworld'
>>> a 'world'
  File "<stdin>", line 1
    a 'world'
      ^
SyntaxError: invalid syntax

甚至是可以直接乘以数字,得到多倍的字符串。

>>> a = 'abcd'
>>> a * 3
'abcdabcdabcd'

 

常用方法

Python 中 str 类型内置了许多有用的方法。现在的目标是记住字符串的提供了这些基础操作就行了,具体的方法名称和用法也许记不清楚,写程序的时候看到编辑器的提醒就会知道了(也可以查看标准库)。

比如检测字符串值的方法。这些方法可以检测字符串值是否符合要求。比如 isdigit 判断字符串值是否是数字,这在类型转换时很重要。

>>> a = '123'
>>> type(a)
<class 'str'>
>>> a.isdigit()
True

类似的,isalnum (alpha 和 number) 检测是否是由字符和数字组成;isalpha 检测是否是由字符组成;isascii 检测是否是由 ascii 码字符组成;isdecimal 检测是否是小数。

>>> a = '123abcd'
>>> a.isalnum()
True
>>> b = 'abcd'
>>> b.isalpha()
True
>>> a.isalpha()
False
>>> a.isascii()
True
>>> a.isdecimal()
False
>>> c = '123'
>>> c.isdecimal()
True
>>> d = '123.1'
>>> d.isdecimal()
False

也有许多检测格式方法。istitle 判断是不是符合标题格式(每隔单词的首字母大写);isupper 判断所有英文字母都是大写的;islower 判断所有英文字母都是小写的。相应的,有 titleupperlower 方法,返回对应的格式。

>>> a = 'Hello Python'
>>> a.istitle()
True
>>> a = 'hello python'
>>> a.istitle()
False
>>> a.title()
'Hello Python'
>>> a = 'HELLO'
>>> a.isupper()
True
>>> a = 'Hello'
>>> a.isupper()
False
>>> a.upper()
'HELLO'
>>> a = 'hello'
>>> a.islower()
True
>>> a = 'Hello'
>>> a.islower()
False
>>> a.lower()
'hello'

还有一些字符串查找和替换的方法。

findindex查找子串在原字符串中的位置,区别是 find 在找不到时会返回 -1, index 在找不到是会引发索引异常。

>>> a = 'abcdefg'
>>>
>>> a.find('bcd')
1
>>> a.find('efg')
4
>>> a.find('hi')
-1
>>> a.index('hi')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: substring not found

startswithendswith 判断是不是以特殊字符串开始和结尾。

>>> a.startswith('abcd')
True
>>> a.startswith('hi')
False
>>> a.endswith('efg')
True
>>> a.endswith('hi')
False

strip 表示删除字符串两头的子串,如果参数为空,就表示删除两头的空格。lstriprstrip 表示删除左边和右边的子串。

>>> a = 'abcdcba'
>>> a.strip('a')
'bcdcb'
>>> a = '  hello python '
>>> a.strip()
'hello python'
>>> a.lstrip()
'hello python '
>>> a.rstrip()
'  hello python'

replace 表示用 新的子串 替换旧的子串。

>>> a = 'hello python'
>>> a.replace('python', 'world')
'hello world'
>>> a.replace('hello', 'hi')
'hi python'

字符串格式化

所谓格式化,是指把变量或者字符串按照指定格式返回(和硬件产品的格式化意思不同)。

比如,现在需要表达 “我喜欢一种水果”,其内容可能是 "我喜欢香蕉",也可能是 "我喜欢苹果",还可能是 "我喜欢葡萄"。那么需要每一种水果都创建一个字符串吗?显然不需要的,我们只要设置一个变量表示水果,在输出的时候使用 '我喜欢%s' % 水果 就可以了。

Python 提供了多种格式化方法。常见的有插值运算符,字符串字面值,和 str.format 方法。

最常见的是使用插值运算符。就是在目标字符串中使用特殊字符,表示这里是一个变量,以及说明变量的格式和类型。

>>> a = 'banana'
>>> b = 'apple'
>>> c = 'grape'
>>> 'i like %s' % a
'i like banana'
>>> 'i like %s' % b
'i like apple'
>>> 'i like %s' % c
'i like grape'

其中 %s 表示字符串,对于要插入的值,如果不是字符串,就会尝试先转换成字符串,然后在插入。有很多种转换类型,比如 %d 表示整数,如果不是整数,就先转换成整数;%f 表示浮点数,注意浮点数的输出小数部分。

>>> "it's %d" % 100
"it's 100"
>>> "it's %d" % 100.0
"it's 100"
>>> "it's %f" % 100.0
"it's 100.000000"
>>> "it's %f" % 100
"it's 100.000000"

除了表示类型,也可以表示格式。在 %5f 表示总共五位数,%5.1f 表示总共五位数,小数部分一位数。

>>> "it's %5.1d" % 100
"it's   100"
>>> "it's %5.1f" % 100
"it's 100.0"

第二种是字符串字面值,也称为 f-string。是使用起来最方便的字符串格式化方法,3.6 版本(现在是 3.9)加入到功能。字符串之前加上 f ,字符串内容中需要替换的位置使用大括号{ } 包含变量。形如 f'I like {name}' ,很直观,写起来也方便。

>>> name = 'apple'
>>> f'i like {name}'
'i like apple'

第三种是 str 类型自带的 format 方法,也是一种很强大的表示方法。和 f-string 类似,在需要替换成变量的位置添加 { } ,不同的是,需要在函数中根据位置,或者名称指定变量的值。形如 'I want a cup of {drink}, would you like a cup of {drink}?'.format(drink='coffee')

>>> drink='coffee'
>>> 'I want a cup of {}, would you like a cup of {}?'.format(drink, drink)
'I want a cup of coffee, would you like a cup of coffee?'
>>> 'I want a cup of {drink}, would you like a cup of {drink}?'.format(drink=drink)
'I want a cup of coffee, would you like a cup of coffee?'

编码和存储

计算机是二进制的,不能直接存储字符串。为了存储字符串,人们把每一个字符都编上号码,根据编码的不同,有许多套字符集。最早的 ascii 只支持英文,然后一些机构都开发了自己的编码,比如中国的 gbk,中日韩的 CJK 等。所谓的乱码,就是使用的软件不能解析字符串的编码。比如,在 ascii 码中 A 的编码是 65,B 的编码是 66,一直到 Z 的编码是 90。

后来人们意识到各个地区使用的编码不同,在软件开发和使用中产生极大的不利。一些机构便开始定义一套完整的字符集,这套编码能够包含世界时绝大部分字符,这是 Unicode 字符集,现在已经包含十三万个字符。由此产生了一些针对 Unicode 字符集的编码,其中最长使用的是 UTF-8。大约 94% 的网页都是使用 UTF-8 编码,由此解决了很多复杂的编码问题。UTF-8 甚至支持表情符号,也就是所谓的 emoji。

Python 使用的正是 UTF-8 编码,而且内置了 ordchr 函数,分别用来查看字符编码和查看编码对应的字符。

>>> ord('1')
49
>>> ord('2')
50
>>> ord('a')
97
>>> ord('中')
20013
>>> ord('学')
23398
>>> ord('😊')
128522
>>> chr(128522)
'😊'
>>> chr(100)
'd'
>>> chr(23398)
'学'

小结

字符串是编程中重要的工具,在信息的表达和传递时起重要的作用。Python 对字符串类型(str)提供了丰富的支持,如果遇到字符串处理的问题,应该先查询 str 自带的方法(https://docs.python.org/zh-cn/3/library/stdtypes.html#text-sequence-type-str