本节书摘来自华章计算机《Python程序设计》一书中的第2章,第2.2节,作者:[美]戴维 I.施奈德(David I. Schneider)著,更多章节内容可以访问云栖社区“华章计算机”公众号查看
2.2 字符串
字符串和数值是Python处理的最为常见的数据类型。句子、短语、单词、字母、名字、电话号码、地址、社会保障号码都是典型的字符串。
2.2.1 字符串字面量
字符串字面量是字符构成的一个序列,并视其为一个整体。字符串中的字符可以是键盘上能够找到的任意字符(例如字母字面量、数字、标点符号和空格)和其他的特殊字符。
在Python程序中,字符串字面量可以表示为单引号(')或者双引号(")包围的一个字符序列。一些字符串的例子如下:
起始和末尾的引号必须是一致的(要么是两个双引号,要么是两个单引号)。当字符串使用双引号定义时,单引号可以直接出现在字符串中,但双引号则不可以。相似地,由单引号定义的字符串可以包含双引号,但不能直接使用单引号。
2.2.2 变量
变量也可以赋值为字符串。与数值类型的变量赋值一样,字符串类型的变量首次出现在赋值语句中时即被创建出来(即变量存在)。当print函数的参数是字符串字面量或者值为字符串的变量时,只有封闭的引号中的字符(不包括引号自身)能够显示出来。
2.2.3 索引和切片
在Python中,字符串中字符所在的位置或索引可以使用数字0、1、2、3…来标识。例如,字符串的第一个字符对应索引0,第二个字符对应索引1等。如果str1是一个字符串变量或字面量,str[i]则是字符串中索引i对应的字符。图2-4展示了字符串“spam & eggs”的所有字符对应的索引。
子字符串或切片是字符串中连续字符的一个序列。例如,以字符串“Just a moment”为例。子字符串“Jus”、“mom”、“nt”起始位置分别为0、7和11,结束位置分别为2、9和12。如果str1是一个字符串,则str1[m:n]是以位置m开始,位置n–1结束的子字符串。图2-5通过可视化帮助理解切片。设想每个字符的索引正好指向相应字符的左边。“spam & eggs”[m:n]是标记为数字m和n的箭头之间的子字符串。例如“spam & eggs”[2:6]是子字符串“am &”,也就是箭头标记2和箭头标记6之间的子字符串。
提示:如果m≥n,也就是说,如果位置m对应的字符不在位置n对应的字符的左边,则str1[m:n]的值为空字符串(""),即不包含字符的字符串。
如果subStr是一个字符串,那么str1.find(subStr)将开始从左向右搜索字符串str1,并返回subStr首次出现的正向索引位置。而str1.rfind(subStr)将开始从右向左搜索字符串str1,并返回字符串subStr首次出现的正向索引位置。如果字符串subStr不在字符串str1中,那么find和rfind方法的返回值为–1。
例1 索引
下面的程序展示了索引的用法。
2.2.4 反向索引
上文讨论的索引是按照字符串自左向右而确定的。Python也支持自右向左地使用负数进行索引。通过反向索引,最右端的字符索引值为-1,它左边的一个字符索引值为-2,以此类推。图2-6显示了字符串”spam & eggs”中字符的反向索引。
例2 反向索引
下面的程序展示了反向索引。
2.2.5 切片的默认边界
在表达式str1[m:n]中,其中一个或者两个边界都是可以忽略的。在这种情况下,左边界m的默认值为0,右边界n的默认值为字符串的长度。也就是,str[:n]包括了从字符串首字符到str1[n-1]之间的所有字符,str1[m:]包括了从str1[m]到字符串末尾的所有字符。切片str1[:]正好表示整个字符串str1。
例3 默认边界
下面的程序展示了默认边界。
2.2.6 字符串连接
两个字符串可以连接起来组成一个新的字符串。这个操作称为连接,可以使用加号来表示。例如,“good”+“bye”为“goodbye”。由字符串、标点符号、函数和方法构成的一个可运算字符串称为字符串表达式。当一个字符串表达式出现在赋值语句或者print函数中时,字符串表达式先进行计算后再赋值或显示。
2.2.7 字符串重复
星号操作符可用来重复地连接一个字符串自身。如果str1是个字符串字面量、变量或者表达式,而n是一个正整数,那么str1 * n的值由n个str1的副本连接得到。
2.2.8 字符串函数和方法
字符串函数操作与数值函数十分相似。它将字符串作为输入并返回相应的值。字符串方法是在字符串上进行处理的一个过程。我们已经看到过两种方法:find和rfind。这两种方法可用于定位索引。而使用方法的一般表达式形式为:
其中括号中可以包含值。与上一节中给出的数值方法类似,字符串函数和方法可以对字符串字面量、变量和表达式进行操作。表2-3给出了str1是字符串“Python”时,一个字符串函数和六个字符串方法。其他更多的字符串方法会在后续章节中陆续介绍。
2.2.9 链式方法
观察以下两行代码:
这两行代码可以合并为如下的一行代码,即链式方法。
链式方法按照从左到右的顺序依次执行。链式调用能够消除临时变量,如上例中的变量praise,因而可以生成简洁的代码。
2.2.10 input函数
input函数提示用户输入数据。一个典型的输入语句是:
当Python执行到这个语句时,将显示“Enter the name of your city:”同时程序中止。在用户键入了他的城市名称并按下〈Enter〉(或〈return〉)键后,变量town将赋值为城市名称(如果变量先前没有创建,变量此时将立即创建)。一个input语句的一般形式为:
其中,prompt是一个要求用户响应的字符串。
例4 解析姓名
下面的程序要求用户输入姓名后解析姓名。当程序运行时,短语“Enter a full name: ”出现后,程序执行过程中止。在用户输入单词并按下〈Enter〉(或〈return〉)键后, 将显示输出的最后两行。
2.2.11 int、float、eval和str函数
如果str1是一个包含整数的字符串,int函数将字符串转换为整型。如果str1是一个包含任意数字的字符串,float函数将字符串转换为浮点型(float函数也可以将整型转换为浮点型)。如果str1是一个包含数值表达式的字符串,eval函数将计算相应表达式,赋值为合适的整型或浮点型。
例5 函数展示
下面的程序展示了int、float、eval函数的用法。
一个input函数通常会返回一个字符串。然而,通过input函数与int、float或eval函数的组合,可以向程序输入数字。例如,考虑以下三个语句:
假设用户输入一个整数25。接着,在上述每个语句执行之后,语句print(age)的输出分别为25、25.0和25。然而,如果某个用户年纪最小,他会输入数字3.5。在执行第一个input语句时,会产生一个回溯的错误消息。而执行第二个或第三个input语句后,print函数会输出3.5。eval函数在任一年龄下均输出正确的结果。
int和float函数比eval函数执行速度要快,因此Python程序员在能够安全使用的前提下更喜欢前者。在本书中,我们均会使用三个函数,但是更喜欢eval函数。
int和float函数也可以应用于数值表达式。如果x是一个整数,int(x)的值为x。如果x是一个浮点数,int函数会丢弃数字中的小数部分。float函数以此类推。eval函数不能应用于数字字面量、变量或表达式。
str函数可以将数字转换为字符串。例如,str(5.6)的值为“5.6”,str(5.)的值为“5.0”。
字符串不可以和一个数字进行连接操作。但是,不正确的语句:
可以用如下正确的语句来替换:
完成两个字符串的连接。
2.2.12 内部文档
程序文档是注释的集合,用于说明程序的用途,变量的目的,程序各个部分执行的任务。要创建一个注释语句,只要以#为行首即可。当程序执行时,将完全忽视注释语句。注释有时也称为附注。在行尾加上#以及必要的信息可以用于注释一行代码。在IDLE编辑器中,按下〈Alt+3〉和〈Alt+4〉键可以注释或不注释选注的代码段。
例6 解析名字
下面重写了例4使用的文档。第一个注释说明了整个程序,第三行的注释给出了变量的含义,最后一个注释描述了它后面两行代码的目的。
使用文档的好处包括:
- 帮助其他人更容易理解程序;
- 帮助自己之后再次阅读时更好地理解程序;
- 由于程序小块部分的用途可以快速确定,大的程序可以更容易阅读。
良好的编程习惯要求程序员应该一边编写代码一边编写注释。事实上,许多软件公司在发布软件之前要求一定程度的文档,部分公司甚至通过代码的文档好坏评价程序员的水平。
2.2.13 行延续
一个长的语句可以通过在行尾(除了最后一行)使用反斜杠()分割成两个或更多行显示。例如,代码行:
可以写成:
Python有个特性可以用来代替反斜杠构成的行延续。任何包含在一组括号中的代码可以分散在多行。由于任何表达式都可以包含在括号里,该特性总是可以被使用。例如,上面的语句可以写成:
行延续的这个方法对于大部分的程序员而言都是一种更好的风格,在本书中无论何时都可以使用。
2.2.14 索引和切片越界
Python不允许字符串中单个字符的索引越界,但是在切片中可以允许索引越界。例如,如果满足:
则print(str1[7])和print(str1[-7])会触发回溯的错误消息IndexError。
如果切片的左边索引过小,切片会从字符串首开始,如果切片的右边索引过大,切片会一直到字符串尾。例如:
注释
- 在本书中,我们通常使用单引号定义单个字符的字符串,而使用双引号定义其他字符串。
- 由于字符串表达式可以通过字面量、变量、函数、方法以及操作符的任意组合来产生字符串,单个字符串或变量也是表达式的一种特殊形式。
- 字符串中的每一个字符都有两个索引—一个正数和一个负数。因此,strValue[m:n]中的数字m和n可以是相反的符号。如果索引m所指字符位于索引n所指字符的左边,则切片将包括由索引所指字符开始和由索引n所指字符的左边字符之间的所有字符组成的子串。例如,"Python"[–4:5]的值为"tho"。当然,如果索引m所指字符不在索引n所指字符的左边,则切片为空字符串。
- 字符串中的字符是无法直接修改的。例如,以下代码试图将单词resort改为单词report,但会产生一个回溯的错误消息。
- 对于字符串,操作符+=意味着一个增量的连接赋值语句。
- IDLE编辑器使用绿色显示字符串,使用红色显示注释。
- 方法名与变量名和函数名类似,都是大小写敏感的。
- 为了代码的易读性,你不应该链式调用三个以上的函数。
- 字符串可看做具有类型str。语句print(dir(str))会显示出所有的字符串方法(但忽略其中所有以双下滑线开始和结尾的方法)。
实践问题 2.2 - 假如0≤m≤n≤len(str1),那么str1[m:n]中有多少个字符?
- 语句“print("Computer".find('E'))?”的输出结果是什么?
习题 2.2
在习题1~4中,给出下列代码行相应的输出。
在习题5~46中,给出表达式的值。
在习题47~70中,给出下列代码行相应的输出。
- 给出一个简单的表达式,能够丢弃字符串的最后一个字符。
- 给出一个简单的表达式,能够丢弃字符串的第一个字符。
- 由8个字符组成的字符串中,第一个字符的反向索引是什么?
- 由8个字符组成的字符串中,最后一个字符的正向索引是什么?
- 判断题:如果str1的长度为n,那么字符串str1[n-1:]会包含str1的最后一个字符。
- 判断题:如果str1的长度为n,那么字符串str1[n-2:] 会包含str1的最后两个字符。
- 判断题:str1[:n]包含str1的前n个字符。
- 判断题:str1[-n:]包含str1的后n个字符。
在习题79~92中,找出其中的错误。
在习题93~96中,编写一行代码来完成程序的每一个步骤,显示结果数据时请使用给定的变量名。
- 发明家 下面的步骤给出了一个著名发明家的名字与出生年份。
(a) 创建变量firstName,并赋值为“Thomas”。
(b) 创建变量middleName,并赋值为“Alva”。
(c) 创建变量lastName,并赋值为“Edison”。
(d) 创建变量yearOfBirth,并赋值为1847。
(e) 用逗号分隔显示发明家的全名以及出生年份。
- 番茄酱的价格 下面的步骤计算番茄酱的价格。
(a) 创建变量item,并赋值为“ketchup”。
(b) 创建变量regularPrice,并赋值为1.80。
(c) 创建变量discount,并赋值为0.27。
(d) 显示短语“1.53 is the sale price of ketchup.”。
- 版权声明 下面的步骤展现了一个版权声明。
(a) 创建变量publisher,并赋值为“Pearson”。
(b) 显示短语“(c) Pearson”。
- 建议 下面的步骤给出了一个建议。
(a) 创建变量prefix,并赋值为“Fore”。
(b) 显示短语“Forewarned is Forearmed.”。
提示:下面的每一个习题,可能的输出结果将显示在一个阴影框中。输入语句以下划线的形式显示。
- 风暴的距离 如果n秒是闪电与雷声之间的间隔时间差,风暴的距离则有n/5英里远。编写一个程序,要求输入闪电与雷声之间的间隔秒数,并返回风暴的距离,结果保留小数点后两位。如图2-7所示。
- 训练心率 美国运动医学院建议你在有氧锻炼时维持你的训练心率。你的训练心率可以通过0.7×(220 – a) + 0.3×r来计算,其中a是你的年龄,r是你的休息心率 (当你第一次醒来后的脉搏)。编写一个程序,要求输入一个人的年龄和休息心率, 并显示他们的训练心率。如图2-8所示。
- 三项全能运动 骑车、跑步、游泳一小时所消耗的卡路里分别为200、475和275。一个人每消耗3 500卡路里可以减掉1磅的体重。编写一个程序,要求输入每项运动的小时数,并显示消耗掉的体重磅数。如图2-9所示。
- 电力成本 某个设备使用的电力成本可通过公式给出:
每千瓦时的成本因地点不同而变化。假设美国本土的消费者当前电力的平均成本为11.76美分/千瓦时。编写一个程序,允许用户计算使用一个电器的成本。图2-10计算了一个电灯持续打开一个月所需的成本。
- 棒球 编写一个程序,要求输入棒球队的名字、赢得比赛的数量、输了比赛的数量,并显示球队名字和相应的胜率。如图2-11所示。
- 价格收益率 编写一个程序,要求输入一个公司当年的每股收益和每股价格,然后显示公司的价格收益率(即每股价格除以每股收益)。如图2-12所示。
- 车速 当汽车在干燥的水泥路面刹车制动滑行d英尺时,公式s =给出了汽车以每小时英里数的估计时速。编写一个程序,要求输入滑行距离,然后给出该车的估计时速。如图2-13所示。提示:x0.5。
- 百分率 编写一个程序,将一个百分比转换为一个小数。如图2-14所示。
- 速度转换 在1954年5月6日,英国运动员Sir Roger Bannister成为了第一个在4分钟内跑完一英里的人。他的平均速度是24.20千米每小时。编写一个程序,要求输入以千米每小时为单位的速度,然后显示以英里每小时为单位的速度。如图2-15所示。提示:1千米等于0.6214英里。
- 服务员小费 编写一个程序,输入账单的金额和小费比例,计算服务员的小费金额。如图2-16所示。
- 等价利息率 来自投资者家乡州的地方政府债券获取的利息是免税的,而在CD上的利息是收税的。因此,为了使得CD能够获得和地方政府债券一样的利息,CD必须要支付一个更高的利息率。利息率必须支付多高取决于投资者的纳税等级。编写一个程序,要求输入纳税等级和地方政府债券利率,然后显示具有相同收益的CD利息率。如图2-17所示。提示:如果纳税等级可以表示为一个小数,那么:
- 市场术语 一个商品的利润是它的售价(selling price)和进价(purchase price)的差异。另外两个市场术语是利润率=利润/进价和毛利率=利润/售价,其中两个结果表示为百分比。编写一个程序,计算一个商品的利润、利润率和毛利率。如图2-18所示。注意当售价是进价的三倍时,利润率为200%。
- 分析数字 编写一个程序,要求输入包含小数点的正数,然后分别显示小数点左边的数位个数和小数点右边的数位个数。如图2-19所示。
- 单词替换 编写一个程序,要求输入一个句子,以及此句中的一个单词和另外一个单词,然后显示用第二个单词替换第一个单词后的句子。如图2-20所示。
- 月份转换 编写一个程序,要求用户输入一个整数的月份数,然后转换为对应时间长度的年月数。如图2-21所示。程序应该使用整除和求模运算符。
- 长度转换 编写一个程序,要求用户输入一个整数的英寸数,然后转换为对应长度的英尺和英寸数。如图2-22所示。程序应该使用整除和求模运算符。
实践问题2.2的解答
- n – m。当m = 0时,str1[0:n]中的字符数目是n。随着数字由0变到m,字符数目也将依次减去m。
- –1。在字符串“Computer”中没有大写的字母E。find方法是区分大小写字母的。