Chapter 8 Strings 第 8 章 字符串
本页译自 Think Python 2e(Allen B. Downey)· Chapter 8 Strings。代码块保留英文原文不翻译;正文段段对照,中文块可用右下角按钮隐藏。
8.1 A string is a sequence 8.1 字符串是序列
A string is a sequence of characters. You can access the characters one at a time with the bracket operator:
sequence)字符。你可以用方括号运算符一次取出一个字符:sequence5
The second statement selects character number 1 from fruit and assigns it to fruit0.
fruit 中选出第 1 号字符,赋给 fruit0。The expression in brackets is called an index. The index indicates which character in the sequence you want (hence the name).
fruit)。索引指明你想要序列里的第几个字符(名字就是这么来的)。But you might not get what you expect:
fruit0011
For most people, the first letter of fruit001 is b, not b. But for computer scientists, the index is an offset from the beginning of the string, and the offset of the first letter is zero.
fruit001 的第一个字母是 b,而不是 b。但对计算机科学家而言,索引是从字符串开头算起的偏移量,而第一个字母的偏移量是零。fruit0018
So b is the 0th letter (“zero-eth”) of fruit002, b is the 1th letter (“one-eth”), and b is the 2th (“two-eth”) letter.
b 是 fruit002 的第 0 个字母("zero-eth"),b 是第 1 个字母("one-eth"),b 是第 2 个字母("two-eth")。You can use any expression, including variables and operators, as an index, but the value of the index has to be an integer. Otherwise you get:
fruit0027
8.2 b00 8.2 b00
b00 is a built-in function that returns the number of characters in a string:
b00 是一个内置函数,返回字符串里字符的个数:fruit0032
To get the last letter of a string, you might be tempted to try something like this:
fruit0033
The reason for the fruit0034 is that there is no letter in fruit003 with the index 6. Since we started counting at zero, the six letters are numbered 0 to 5. To get the last character, you have to subtract 1 from fruit0:
fruit0037 ,是因为 fruit003 里没有索引为 6 的字母。既然我们从零开始数,这六个字母编号是 0 到 5。要取最后一个字符,得从 fruit0 里减 1:fruit0040
Alternatively, you can use negative indices, which count backward from the end of the string. The expression fruit0041 yields the last letter, fruit0042 yields the second to last, and so on.
fruit0043 得到最后一个字母,fruit0044 得到倒数第二个,依此类推。8.3 Traversal with a b00 loop 8.3 用 b00 循环遍历
A lot of computations involve processing a string one character at a time. Often they start at the beginning, select each character in turn, do something to it, and continue until the end. This pattern of processing is called a traversal. One way to write a traversal is with a fruit loop:
fruit0048)。写遍历的一种方法是用 fruit 循环:fruit0050
This loop traverses the string and displays each letter on a line by itself. The loop condition is fruit0051 , so when fruit is equal to the length of the string, the condition is false, and the body of the loop is not executed. The last character accessed is the one with the index fruit0053 , which is the last character in the string.
fruit0054 ,所以当 fruit 等于字符串长度时,条件为假,循环体不再执行。被访问的最后一个字符,其索引为 fruit0056 ,也就是字符串的最后一个字符。Exercise 1
Write a function that takes a string as an argument and displays the letters backward, one per line.
Another way to write a traversal is with a b00 loop:
b00 循环:fruit0059
Each time through the loop, the next character in the string is assigned to the variable b000. The loop continues until no characters are left.
b000。循环一直进行到没有字符剩下为止。The following example shows how to use concatenation (string addition) and a b00 loop to generate an abecedarian series (that is, in alphabetical order). In Robert McCloskey’s book Make Way for Ducklings, the names of the ducklings are Jack, Kack, Lack, Mack, Nack, Ouack, Pack, and Quack. This loop outputs these names in order:
b00 循环,生成一组按字母顺序排列的名字。在 Robert McCloskey 的《让路给小鸭子》里,小鸭子的名字是 Jack、Kack、Lack、Mack、Nack、Ouack、Pack 和 Quack。这个循环按次序把它们的名字打印出来:fruit0064
The output is:
fruit0065
Of course, that’s not quite right because “Ouack” and “Quack” are misspelled.
Exercise 2
Modify the program to fix this error.
8.4 String slices 8.4 字符串切片
A segment of a string is called a slice. Selecting a slice is similar to selecting a character:
fruit)。选取切片和选取字符类似:fruit0067
The operator fruit returns the part of the string from the “n-eth” character to the “m-eth” character, including the first but excluding the last. This behavior is counterintuitive, but it might help to imagine the indices pointing between the characters, as in Figure 8.1.
fruit 返回字符串中从"第 n 个"字符到"第 m 个"字符之间的部分,包含第一个、但不包含最后一个。这种行为有违直觉,不过如果把索引想象成指向字符之间的位置,像图 8.1 那样,也许会好理解些。Figure 8.1: Slice indices.
If you omit the first index (before the colon), the slice starts at the beginning of the string. If you omit the second index, the slice goes to the end of the string:
fruit0070
If the first index is greater than or equal to the second the result is an empty string, represented by two quotation marks:
fruit0071
An empty string contains no characters and has length 0, but other than that, it is the same as any other string.
Exercise 3
Given that fruit is a string, what does fruit007 mean?
fruit 是一个字符串,那么 fruit007 是什么意思?8.5 Strings are immutable 8.5 字符串不可变
It is tempting to use the b0 operator on the left side of an assignment, with the intention of changing a character in a string. For example:
b0 运算符,打算修改字符串里的某个字符。例如:fruit0078
The “object” in this case is the string and the “item” is the character you tried to assign. For now, an object is the same thing as a value, but we will refine that definition later. An item is one of the values in a sequence.
fruit0)和"值"当成一回事,不过后面我们会把这个定义细化。元素(b000)是序列中的某个值。The reason for the error is that strings are immutable, which means you can’t change an existing string. The best you can do is create a new string that is a variation on the original:
fruit0081)的,也就是说你没法改动一个已有的字符串。你顶多只能新建一个字符串,作为原字符串的某种变体:fruit0082
This example concatenates a new first letter onto a slice of fruit008. It has no effect on the original string.
fruit008 的一个切片上。这对原字符串没有任何影响。8.6 Searching 8.6 搜索
What does the following function do?
fruit0085
In a sense, b000 is the opposite of the b0 operator. Instead of taking an index and extracting the corresponding character, it takes a character and finds the index where that character appears. If the character is not found, the function returns b0.
b000 是 b0 运算符的反操作。它不是接收一个索引、取出对应的字符,而是接收一个字符、找出该字符出现的索引。如果没找到这个字符,函数就返回 b0。This is the first example we have seen of a fruit0 statement inside a loop. If fruit0093 , the function breaks out of the loop and returns immediately.
fruit0 语句的第一个例子。只要 fruit0095 ,函数就跳出循环、立即返回。If the character doesn’t appear in the string, the program exits the loop normally and returns b0.
b0。This pattern of computation—traversing a sequence and returning when we find what we are looking for—is called a search.
fruit0)。Exercise 4
Modify b000 so that it has a third parameter, the index in b000 where it should start looking.
b000,让它带第三个实参,即开始在 b000 里查找的位置索引。8.7 Looping and counting 8.7 循环与计数
The following program counts the number of times the letter b appears in a string:
b 在一个字符串中出现的次数:fruit0105
This program demonstrates another pattern of computation called a counter. The variable fruit is initialized to 0 and then incremented each time an b is found. When the loop exits, fruit contains the result—the total number of b’s.
fruit01)的计算模式。变量 fruit 初始化为 0,每发现一个 b 就加 1。循环结束时,fruit 里就是结果——b 的总数。Exercise 5
Encapsulate this code in a function named fruit, and generalize it so that it accepts the string and the letter as arguments.
fruit 的函数,并把它一般化,让字符串和字母都作为实参传入。Exercise 6
Rewrite this function so that instead of traversing the string, it uses the three-parameter version of b000 from the previous section.
b000 版本。8.8 String methods 8.8 字符串方法
A method is similar to a function—it takes arguments and returns a value—but the syntax is different. For example, the method fruit takes a string and returns a new string with all uppercase letters:
fruit0)和函数相似——它接收实参、返回一个值——但语法不同。例如,fruit 方法接收一个字符串,返回一个把所有字母都变成大写的新字符串:Instead of the function syntax fruit0122 , it uses the method syntax fruit0123 .
fruit0124 ,而是方法语法 fruit0125 。fruit0126
This form of dot notation specifies the name of the method, fruit, and the name of the string to apply the method to, b000. The empty parentheses indicate that this method takes no argument.
fruit,以及要对其调用方法的字符串的名字 b000。那对空括号表示这个方法不接收实参。A method call is called an invocation; in this case, we would say that we are invoking fruit on the b000.
fruit0133 );在这里我们会说,我们在 b000 上调用(invoking)fruit。As it turns out, there is a string method named b000 that is remarkably similar to the function we wrote:
b000 的字符串方法,和我们刚才写的函数惊人地相似:fruit0138
In this example, we invoke b000 on b000 and pass the letter we are looking for as a parameter.
b000 上调用 b000,把要找的字母作为实参传进去。Actually, the b000 method is more general than our function; it can find substrings, not just characters:
b000 方法比我们的函数更通用;它不仅能找单个字符,还能找子串:fruit0145
It can take as a second argument the index where it should start:
fruit0146
And as a third argument the index where it should stop:
fruit0147
This search fails because b does not appear in the index range from b to b (not including b).
b 并不出现在从 b 到 b(不含 b)的索引范围内。Exercise 7
There is a string method called fruit that is similar to the function in the previous exercise. Read the documentation of this method and write an invocation that counts the number of bs in fruit015.
fruit 的字符串方法,和上一道习题里的函数类似。阅读这个方法的文档,写一个方法调用,统计 fruit016 里 b 的个数。Exercise 8
Read the documentation of the string methods at fruit0162 . You might want to experiment with some of them to make sure you understand how they work. fruit and fruit01 are particularly useful.
fruit0165 。你也许想亲自动手试其中几个,确认自己理解它们的工作原理。fruit 和 fruit01 尤其有用。The documentation uses a syntax that might be confusing. For example, in fruit0168 , the brackets indicate optional arguments. So b00 is required, but fruit is optional, and if you include fruit, then b00 is optional.
fruit0173 中,方括号表示可选实参(fruit0174 )。所以 b00 是必需的,而 fruit 可选,如果你写了 fruit,那么 b00 也是可选的。8.9 The b0 operator 8.9 b0 运算符
The word b0 is a boolean operator that takes two strings and returns b000 if the first appears as a substring in the second:
b0 是一个布尔运算符,接收两个字符串,如果第一个作为子串出现在第二个里面,就返回 b000:fruit0185
For example, the following function prints all the letters from fruit that also appear in fruit:
fruit 中同时也出现在 fruit 里的所有字母:fruit0190
With well-chosen variable names, Python sometimes reads like English. You could read this loop, “for (each) letter in (the first) word, if (the) letter (appears) in (the second) word, print (the) letter.”
Here’s what you get if you compare apples and oranges:
fruit0191
8.10 String comparison 8.10 字符串比较
The relational operators work on strings. To see if two strings are equal:
fruit0192
Other relational operations are useful for putting words in alphabetical order:
fruit0193
Python does not handle uppercase and lowercase letters the same way that people do. All the uppercase letters come before all the lowercase letters, so:
fruit0194
A common way to address this problem is to convert strings to a standard format, such as all lowercase, before performing the comparison. Keep that in mind in case you have to defend yourself against a man armed with a Pineapple.
8.11 Debugging 8.11 调试
When you use indices to traverse the values in a sequence, it is tricky to get the beginning and end of the traversal right. Here is a function that is supposed to compare two words and return b000 if one of the words is the reverse of the other, but it contains two errors:
b000,但它里面藏着两个错误:fruit0197
The first b0 statement checks whether the words are the same length. If not, we can return fruit immediately and then, for the rest of the function, we can assume that the words are the same length. This is an example of the guardian pattern in Section 6.8.
b0 语句检查两个单词长度是否相同。如果不同,我们可以立即返回 fruit,之后在函数其余部分就可以假定两个单词长度相同。这是 6.8 节里"守门人模式"的一个例子。b and b are indices: b traverses fruit forward while b traverses fruit backward. If we find two letters that don’t match, we can return fruit immediately. If we get through the whole loop and all the letters match, we return b000.
b 和 b 都是索引:b 正向遍历 fruit,而 b 反向遍历 fruit。如果找到两个不匹配的字母,就立即返回 fruit。如果整个循环走完、所有字母都匹配,就返回 b000。If we test this function with the words “pots” and “stop”, we expect the return value b000, but we get an IndexError:
b000,但得到的却是一个 IndexError:fruit0220
For debugging this kind of error, my first move is to print the values of the indices immediately before the line where the error appears.
fruit0221
Now when I run the program again, I get more information:
fruit0222
The first time through the loop, the value of b is 4, which is out of range for the string fruit0. The index of the last character is 3, so the initial value for b should be fruit0226 .
b 的值是 4,而对于字符串 fruit0 来说这已经越界了。最后一个字符的索引是 3,所以 b 的初始值应该是 fruit0230 。If I fix that error and run the program again, I get:
fruit0231
This time we get the right answer, but it looks like the loop only ran three times, which is suspicious. To get a better idea of what is happening, it is useful to draw a state diagram. During the first iteration, the frame for fruit0232 is shows in Figure 8.2.
fruit0233 的栈帧如图 8.2 所示。Figure 8.2: State diagram.
I took a little license by arranging the variables in the frame and adding dotted lines to show that the values of b and b indicate characters in fruit and fruit.
b 和 b 的值分别指向 fruit 和 fruit 里的字符。Exercise 9
Starting with this diagram, execute the program on paper, changing the values of b and b during each iteration. Find and fix the second error in this function.
b 和 b 的值。找出并修正这个函数里的第二个错误。8.12 Glossary 8.12 术语表
- object:
- Something a variable can refer to. For now, you can use “object” and “value” interchangeably.
- sequence:
- An ordered set; that is, a set of values where each value is identified by an integer index.
- item:
- One of the values in a sequence.
- index:
- An integer value used to select an item in a sequence, such as a character in a string.
- slice:
- A part of a string specified by a range of indices.
- empty string:
- A string with no characters and length 0, represented by two quotation marks.
- immutable:
- The property of a sequence whose items cannot be assigned.
- traverse:
- To iterate through the items in a sequence, performing a similar operation on each.
- search:
- A pattern of traversal that stops when it finds what it is looking for.
- counter:
- A variable used to count something, usually initialized to zero and then incremented.
- method:
- A function that is associated with an object and called using dot notation.
- invocation:
- A statement that calls a method.
- object 对象:
- 变量可以指向的东西。目前你可以把"对象"和"值"当作同义词使用。
- sequence 序列:
- 一个有序集合;也就是说,一组值,其中每个值都由一个整数索引来标识。
- item 元素:
- 序列中的某一个值。
- index 索引:
- 用来从序列中选出某个值(比如字符串里的某个字符)的整数值。
- slice 切片:
- 由一段索引范围所指定的字符串的一部分。
- empty string 空字符串:
- 不含任何字符、长度为 0 的字符串,用一对引号表示。
- immutable 不可变:
- 序列的一种属性,指其元素不可被赋值。
- traverse 遍历:
- 依次经过序列中的各个值,对每个值执行类似的操作。
- search 搜索:
- 一种遍历模式,找到要找的东西时就停下来。
- counter 计数器:
- 用来计数的变量,通常初始化为 0,然后不断递增。
- method 方法:
- 与某个对象相关联、用点记法调用的函数。
- invocation 方法调用:
- 调用一个方法的语句。
8.13 Exercises 8.13 习题
Exercise 10
A string slice can take a third index that specifies the “step size;” that is, the number of spaces between successive characters. A step size of 2 means every other character; 3 means every third, etc.
fruit0246
A step size of -1 goes through the word backwards, so the slice fruit0 generates a reversed string.
fruit0 会生成一个反转后的字符串。Use this idiom to write a one-line version of fruit0249 from Exercise 6.
fruit0250 的单行版本。Exercise 11
The following functions are all intended to check whether a string contains any lowercase letters, but at least some of them are wrong. For each function, describe what the function actually does (assuming that the parameter is a string).
fruit0251
Exercise 12
ROT13 is a weak form of encryption that involves “rotating” each letter in a word by 13 places. To rotate a letter means to shift it through the alphabet, wrapping around to the beginning if necessary, so ’A’ shifted by 3 is ’D’ and ’Z’ shifted by 1 is ’A’.
Write a function called fruit0252 that takes a string and an integer as parameters, and that returns a new string that contains the letters from the original string “rotated” by the given amount.
fruit0253 的函数,接收一个字符串和一个整数作为形参,返回一个新的字符串,其中的字母按给定数量从原字符串"旋转"而来。For example, “cheer” rotated by 7 is “jolly” and “melon” rotated by -10 is “cubed”.
You might want to use the built-in functions b00, which converts a character to a numeric code, and b00, which converts numeric codes to characters.
b00(把字符转换成数字编码)和 b00(把数字编码转换回字符)。Potentially offensive jokes on the Internet are sometimes encoded in ROT13. If you are not easily offended, find and decode some of them. Solution: fruit0258 .
fruit0259 。