|
| 1 | +>你们又听见有吩咐古人的话,说:“不可背誓,所起的誓,总要向主谨守”。只是我告诉你们,什么誓都不可起,不可指着天起誓,因为天是神的座位。不可指着地起誓,因为地是他的脚蹬,也不可指着耶路撒冷起誓,因为耶路撒冷是大君的京城。又不可指着你的头起誓,因为你不能使一根头发变黑变白了。你的话,是,就说是。不是,就说不是。若再多说,就是出于那恶者。(Matthew 5:33-37) |
| 2 | +
|
| 3 | +#字符串(3) |
| 4 | + |
| 5 | +关于字符串的内容,已经有两节进行介绍了。不过,它是一个话题中心,还要再继续。 |
| 6 | + |
| 7 | +例如这样一个字符串`python`,还记得前面对字符串的定义吗?它就是几个字符:p,y,t,h,o,n,排列起来。这种排列是非常严格的,不仅仅是字符本身,而且还有顺序,换言之,如果某个字符换了,就编程一个新字符串了;如果这些字符顺序发生变化了,也成为了一个新字符串。 |
| 8 | + |
| 9 | +在python中,把像字符串这样的对象类型(后面还会冒出来类似的其它有这种特点的对象类型,比如列表),统称为序列。顾名思义,序列就是“有序排列”。 |
| 10 | + |
| 11 | +比如水泊梁山的108个好汉(里面分明也有女的,难道女汉子是从这里来的吗?),就是一个“有序排列”的序列。从老大宋江一直排到第108位金毛犬段景。在这个序列中,每个人有编号,编号和每个人一一对应。1号是宋江,2号是卢俊义。反过来,通过每个人的姓名,也能找出他对应的编号。武松是多少号?14号。李逵呢?22号。 |
| 12 | + |
| 13 | +在python中,给这些编号取了一个文雅的名字,叫做**索引**(别的编程语言也这么称呼,不是python独有的。)。 |
| 14 | + |
| 15 | +##索引和切片 |
| 16 | + |
| 17 | +前面用梁山好汉的为例说明了索引。再看python中的例子: |
| 18 | + |
| 19 | + >>> lang = "study python" |
| 20 | + >>> lang[0] |
| 21 | + 's' |
| 22 | + >>> lang[1] |
| 23 | + 't' |
| 24 | + |
| 25 | +有一个字符串,通过赋值语句赋给了变量lang。如果要得到这个字符串的第一个单词`s`,可以用`lang[0]`。当然,如果你不愿意通过赋值语句,让变量lang来指向那个字符串,也可以这样做: |
| 26 | + |
| 27 | + >>> "study python"[0] |
| 28 | + 's' |
| 29 | + |
| 30 | +效果是一样的。因为lang是标签,就指向了`"study python"`字符串。当让python执行`lang[0]`的时候,就是要转到那个字符串对象,如同上面的操作一样。只不过,如果不用lang这么一个变量,后面如果再写,就费笔墨了,要每次都把那个字符串写全了。为了省事,还是复制给一个变量吧。变量就是字符串的代表了。 |
| 31 | + |
| 32 | +字符串这个序列的排序方法跟梁山好汉有点不同,第一个不是用数字1表示,而是用数字0表示。不仅仅python,其它很多语言都是从0开始排序的。为什么这样做呢?这就是规定。当然,这个规定是有一定优势的。此处不展开,有兴趣的网上去google一下,有专门对此进行解释的文章。 |
| 33 | + |
| 34 | +|0|1|2|3|4|5|6|7|8|9|10|11| |
| 35 | +|-|-|-|-|-|-|-|-|-|-|--|--| |
| 36 | +|s|t|u|d|y| |p|y|t|h|o |n | |
| 37 | + |
| 38 | +上面的表格中,将这个字符串从第一个到最后一个进行了排序,特别注意,两个单词中间的那个空格,也占用了一个位置。 |
| 39 | + |
| 40 | +通过索引能够找到该索引所对应的字符,那么反过来,能不能通过字符,找到其在字符串中的索引值呢?怎么找? |
| 41 | + |
| 42 | + >>> lang.index("p") |
| 43 | + 6 |
| 44 | + |
| 45 | +就这样,是不是已经能够和梁山好汉的例子对上号了?只不过区别在于第一个的索引值是0。 |
| 46 | + |
| 47 | +如果某一天,宋大哥站在大石头上,向着各位弟兄大喊:“兄弟们,都排好队。”等兄弟们排好之后,宋江说:“现在给各位没有老婆的兄弟分配女朋友,我这里已经有了名单,我念叨的兄弟站出来。不过我是按照序号来念的。第29号到第34号先出列,到旁边房子等候分配女朋友。” |
| 48 | + |
| 49 | +在前面的例子中lang[1]能够得到原来字符串的第二个字符t,就相当于从原来字符串中把这个“切”出来了。不过,我们这么“切”却不影响原来字符串的完整性,当然可以理解为将那个字符t赋值一份拿出来了。 |
| 50 | + |
| 51 | +那么宋江大哥没有一个一个“切”,而是一下将几个兄弟叫出来。在python中也能做类似事情。 |
| 52 | + |
| 53 | + >>> lang |
| 54 | + 'study python' #在前面“切”了若干的字符之后,再看一下该字符串,还是完整的。 |
| 55 | + >>> lang[2:9] |
| 56 | + 'udy pyt' |
| 57 | + |
| 58 | +通过`lang[2:9]`要得到部分(不是一个)字符,从返回的结果中可以看出,我们得到的是序号分别对应着`2,3,4,5,6,7,8`(跟上面的表格对应一下)字符(包括那个空格)。也就是,这种获得部分字符的方法中,能够得到开始需要的以及最后一个序号之前的所对应的字符。有点拗口,自己对照上面的表格数一数就知道了。简单说就是包括开头,不包括结尾。 |
| 59 | + |
| 60 | +上述,不管是得到一个还是多个,通过索引得到字符的过程,称之为**切片**。 |
| 61 | + |
| 62 | +切片是一个很有意思的东西。可以“切”出不少花样呢? |
| 63 | + |
| 64 | + >>> lang |
| 65 | + 'study python' |
| 66 | + >>> b = lang[1:] #得到从1号到最末尾的字符,这时最后那个需要不用写 |
| 67 | + >>> b |
| 68 | + 'tudy python' |
| 69 | + >>> c = lang[:] #得到所有字符 |
| 70 | + >>> c |
| 71 | + 'study python' |
| 72 | + >>> d = lang[:10] #得到从第一个到10号之前的字符 |
| 73 | + >>> d |
| 74 | + 'study pyth' |
| 75 | + |
| 76 | +在获取切片的时候,如果分号的前面或者后面的序号不写,就表示是到最末(后面的不写)或第一个(前面的不写) |
| 77 | + |
| 78 | +`lang[:10]`的效果和`lang[0:10]`是一样的。 |
| 79 | + |
| 80 | + >>> e = lang[0:10] |
| 81 | + >>> e |
| 82 | + 'study pyth' |
| 83 | + |
| 84 | +那么,`lang[1:]`和`lang[1:11]`效果一样吗?请思考后作答。 |
| 85 | + |
| 86 | + >>> lang[1:11] |
| 87 | + 'tudy pytho' |
| 88 | + >>> lang[1:] |
| 89 | + 'tudy python' |
| 90 | + |
| 91 | +果然不一样,你思考对了吗?原因就是前述所说的,如果分号后面有数字,所得到的切片,不包含该数字所对应的序号(前包括,后不包括)。那么,是不是可以这样呢?`lang[1:12]`,不包括12号(事实没有12号),是不是可以得到1到11号对应的字符呢? |
| 92 | + |
| 93 | + >>> lang[1:12] |
| 94 | + 'tudy python' |
| 95 | + >>> lang[1:13] |
| 96 | + 'tudy python' |
| 97 | + |
| 98 | +果然是。并且不仅仅后面写12,写13,也能得到同样的结果。但是,我这个特别要提醒,这种获得切片的做法在编程实践中是不提倡的。特别是如果后面要用到循环的时候,这样做或许在什么时候遇到麻烦。 |
| 99 | + |
| 100 | +如果在切片的时候,冒号左右都不写数字,就是前面所操作的`c = lang[:]`,其结果是变量c的值与原字符串一样,也就是“复制”了一份。注意,这里的“复制”我打上了引号,意思是如同复制,是不是真的复制呢?可以用下面的方式检验一下 |
| 101 | + |
| 102 | + >>> id(c) |
| 103 | + 3071934536L |
| 104 | + >>> id(lang) |
| 105 | + 3071934536L |
| 106 | + |
| 107 | +`id()`的作用就是查看该对象在内存地址(就是在内存中的位置编号)。从上面可以看出,两个的内存地址一样,说明c和lang两个变量指向的是同一个对象。用`c=lang[:]`的方式,并没有生成一个新的字符串,而是将变量c这个标签也贴在了原来那个字符串上了。 |
| 108 | + |
| 109 | + >>> lang = "study python" |
| 110 | + >>> c = lang |
| 111 | + |
| 112 | +如果这样操作,变量c和lang是不是指向同一个对象呢?或者两者所指向的对象内存地址如何呢?看官可以自行查看。 |
| 113 | + |
| 114 | +##字符串基本操作 |
| 115 | + |
| 116 | +字符串是一种序列,所有序列都有如下基本操作: |
| 117 | + |
| 118 | +1. len():求序列长度 |
| 119 | +2. + :连接2个序列 |
| 120 | +3. * : 重复序列元素 |
| 121 | +4. in :判断元素是否存在于序列中 |
| 122 | +5. max() :返回最大值 |
| 123 | +6. min() :返回最小值 |
| 124 | +7. cmp(str1,str2) :比较2个序列值是否相同 |
| 125 | + |
| 126 | +通过下面的例子,将这几个基本操作在字符串上的使用演示一下: |
| 127 | + |
| 128 | + >>> str1 + str2 |
| 129 | + 'abcdabcde' |
| 130 | + >>> str1 + "-->" + str2 |
| 131 | + 'abcd-->abcde' |
| 132 | + |
| 133 | +这其实就是拼接,不过在这里,看官应该有一个更大的观念,我们现在只是学了字符串这一种序列,后面还会遇到列表、元组两种序列,都能够如此实现拼接。 |
| 134 | + |
| 135 | + >>> "a" in str1 |
| 136 | + True |
| 137 | + >>> "de" in str1 |
| 138 | + False |
| 139 | + >>> "de" in str2 |
| 140 | + True |
| 141 | + |
| 142 | +`in`用来判断某个字符串是不是在另外一个字符串内,或者说判断某个字符串内是否包含某个字符串,如果包含,就返回`True`,否则返回`False`。 |
| 143 | + |
| 144 | + >>> max(str1) |
| 145 | + 'd' |
| 146 | + >>> max(str2) |
| 147 | + 'e' |
| 148 | + >>> min(str1) |
| 149 | + 'a' |
| 150 | + |
| 151 | +一个字符串中,每个字符在计算机内都是有编码的,也就是对应着一个数字,`min()`和`max()`就是根据这个数字里获得最小值和最大值,然后对应出相应的字符。关于这种编号是多少,看官可以google有关字符编码,或者ASCII编码什么的,很容易查到。 |
| 152 | + |
| 153 | + >>> cmp(str1, str2) |
| 154 | + -1 |
| 155 | + |
| 156 | +将两个字符串进行比较,也是首先将字符串中的符号转化为对一个的数字,然后比较。如果返回的数值小于零,说明第一个小于第二个,等于0,则两个相等,大于0,第一个大于第二个。为了能够明白其所以然,进入下面的分析。 |
| 157 | + |
| 158 | + >>> ord('a') |
| 159 | + 97 |
| 160 | + >>> ord('b') |
| 161 | + 98 |
| 162 | + >>> ord(' ') |
| 163 | + 32 |
| 164 | + |
| 165 | +`ord()`是一个内建函数,能够返回某个字符(注意,是一个字符,不是多个字符组成的串)所对一个的ASCII值(是十进制的),字符a在ASCII中的值是97,空格在ASCII中也有值,是32。顺便说明,反过来,根据整数值得到相应字符,可以使用`chr()`: |
| 166 | + |
| 167 | + >>> chr(97) |
| 168 | + 'a' |
| 169 | + >>> chr(98) |
| 170 | + 'b' |
| 171 | + |
| 172 | +于是,就得到如下比较结果了: |
| 173 | + |
| 174 | + >>> cmp("a","b") #a-->97, b-->98, 97小于98,所以a小于b |
| 175 | + -1 |
| 176 | + >>> cmp("abc","aaa") |
| 177 | + 1 |
| 178 | + >>> cmp("a","a") |
| 179 | + 0 |
| 180 | + |
| 181 | +看看下面的比较,是怎么进行的呢? |
| 182 | + |
| 183 | + >>> cmp("ad","c") |
| 184 | + -1 |
| 185 | + |
| 186 | +在字符串的比较中,是两个字符串的第一个字符先比较,如果相等,就比较下一个,如果不相等,就返回结果。直到最后,如果还相等,就返回0。位数不够时,按照没有处理(注意,没有不是0,0在ASCII中对应的是NUL),位数多的那个天然大了。ad中的a先和后面的c进行比较,显然a小于c,于是就返回结果-1。如果进行下面的比较,是最容易让人迷茫的。看官能不能根据刚才阐述的比较远离理解呢? |
| 187 | + |
| 188 | + >>> cmp("123","23") |
| 189 | + -1 |
| 190 | + >>> cmp(123,23) #也可以比较整数,这时候就是整数的直接比较了。 |
| 191 | + 1 |
| 192 | + |
| 193 | +还有一个就是字符串中的“乘法”,这个乘法,就是重复那个字符串的含义。在某些时候很好用的。比如我要打印一个华丽的分割线: |
| 194 | + |
| 195 | + >>> str1*3 |
| 196 | + 'abcdabcdabcd' |
| 197 | + >>> print "-"*20 #不用输入很多个`-` |
| 198 | + -------------------- |
| 199 | + |
| 200 | +------ |
| 201 | + |
| 202 | +[总目录](./index.md) | [上节:字符串(2)](./107.md) | [下节:字符串(4)](./109.md) |
| 203 | + |
| 204 | +如果你认为有必要打赏我,请通过支付宝: **[email protected]**,不胜感激。 |
0 commit comments