本篇文章介绍的这些Python方法(也可以称为Python函数),很多既可以用于普通字符串对象,又可以用于unicode字符串对象。但是为了方便起见,作者只会给出普通字符串对象相关的C源码(也就是定义在Objects/stringobject.c文件中的代码)...

    页面导航: 英文教程的下载地址:

    本篇文章是根据英文教程《Python Tutorial》来写的学习笔记。该英文教程的下载地址如下:

    百度盘地址:http://pan.baidu.com/s/1c0eXSQG

    DropBox地址:点此进入DropBox链接

    Google Drive:点此进入Google Drive链接

    这是学习笔记,不是翻译,因此,内容上会与英文原著有些不同。以下记录是根据英文教程的第九章来写的。(文章中的部分链接,包括下载链接,可能需要通过代理访问!)

    本篇文章也会涉及到Python的C源代码,这些C源码都是2.7.8版本的。想使用gdb来调试python源代码的话,就需要按照前面"Python基本的操作运算符"文章中所说的,使用configure --with-pydebug命令来重新编译安装python。

    如果Python的官方网站取消了Python-2.7.8.tgz的源码包的话,可以在以下两个链接中下载到:

    DropBox:Python-2.7.8.tgz的DropBox网盘链接

    Google Drive:Python-2.7.8.tgz的Google Drive网盘链接

    本篇文章介绍的这些Python方法(也可以称为Python函数),很多既可以用于普通字符串对象,又可以用于unicode字符串对象。但是为了方便起见,作者只会给出普通字符串对象相关的C源码(也就是定义在Objects/stringobject.c文件中的代码)。对于那些只能用于unicode字符串对象的方法(如下面要介绍的isnumeric与isdecimal),才会给出unicode字符串对象相关的C源码(主要定义在Objects/unicodeobject.c文件里)。

字符串相关的函数:

    Python中包含的,和字符串相关的一些函数(或者叫方法),如下表所示(表格函数名部分的S表示字符串对象,可以通过点击函数名,来跳转到对应的详细介绍部分):

函数名 相关描述
S.capitalize()
这里S表示字符串对象,该方法会创建一个S的copy(拷贝),
同时将copy字符串的首字母设置为大写,
余下的其他字母都设置为小写。最后将该copy返回。
 
S.center(width[, fillchar])
当center方法的width参数小于等于S的字符个数时,就直接将S返回。
当width参数大于S的字符个数时,就会创建一个S的copy(拷贝),
并在copy字符串的左右两侧填充fillchar字符,如果fillchar没提供的话,
默认就使用空格符来填充,通过左右填充让copy字符串能居中对齐。
最后将这个copy字符串对象返回。
 
S.count(sub[, start[, end]])
该方法会在S字符串对象里统计sub子字符串的个数,start与end是可选的参数,用于确定
S字符串对象的查找范围,相当于在S[start:end]中统计sub的个数。
 
S.decode([encoding[,errors]])
该方法里的两个参数都是可选的,该方法会将字符串S根据encoding参数进行解码操作,
例如,当encoding为base64时,就可以将字符串按照base64进行解码。errors参数用于
设置当解码出错时的处理方式,例如当errors为ignore时,解码出错时会忽略错误继续执行。当
errors为strict时,会抛出相关的异常。strict是errors参数的缺省值。
返回的是一个新的解码后的字符串对象。
 
S.encode([encoding[,errors]])
该方法会将字符串S根据encoding参数,进行编码操作。返回的是一个新的编码后的字符串对象。
 
S.endswith(suffix[, start[, end]])
该方法的start与end参数是可选的,用于检测S[start:end]字符串是否是以suffix子字符串结尾的。
 
S.expandtabs([tabsize])
该方法会返回S的一个copy(拷贝),并将copy字符串里的所有的tab制表符,
都根据tab边界替换为特定数量的空格符,
tabsize参数是可选的,用于指定tab边界的字符宽度,tabsize的缺省值为8 。
 
S.find(sub [,start [,end]])
该方法的start与end参数是可选的,用于在S[start:end]中查找sub子字符串,如果找到了sub,
就返回sub在S里的偏移值(注意是S里的偏移值,而不是S[start:end]里的偏移值,下面会举例说明),
如果找不到,则返回-1 。
 
S.index(sub [,start [,end]])
该方法也是在S[start:end]中查找sub子字符串,但是与find方法的区别在于:当index方法找不到
sub子字符串时,会抛出ValueError异常,而不会像find那样返回-1。
 
S.isalnum()
该方法用于检测字符串S里的所有字符,是否都是字母或数字。如果都是字母或数字,就返回True。
如果其中有一个字符不是字母或数字的话,则返回False 。
 
S.isalpha()
如果S里的所有字符都是字母的话(S中必须至少有一个字符),该方法就返回True,
否则返回False 。
 
S.isdigit()
如果S里的所有字符都是数字的话(S中必须至少有一个字符),该方法就返回True,
否则返回False 。
 
S.islower()
如果S中所有大小写敏感的字符都是小写的话(S中必须至少包含一个大小写敏感的字符),该方法
就返回True,否则返回False 。
 
S.isnumeric()
这里的S必须是unicode字符串,因为isnumeric方法只存在于unicode字符串对象中。
该方法用于判断字符串里的字符是否都是NUMERIC数字类型,要判断一个unicode字符是否是
数字类型,是由该字符对应的_PyUnicode_TypeRecord结构
(该结构位于python源码的Objects/unicodectype.c文件中)的flags字段来决定的,当flags字段存在
NUMERIC_MASK二进制位时,对应的字符就是NUMERIC数字类型。
例如,u'四'就是NUMERIC数字类型。前缀u表示'四'为unicode编码的字符串。因此,
u'四'.isnumeric()在执行时,就会返回True 。
 
S.isspace()
该方法用于判断S里的所有字符是否都是whitespace(空白符),空白符可以是:空格符,\f(换页符),
\n(换行符),\r(回车符),\t(水平制表符),以及\v(垂直制表符)。
 
S.istitle()
该方法用于判断S是否是标题样式的字符串。标题样式的字符串里,每个单词除了首字母是大写字母外,
单词的其余部分都是小写字母。字符串中的非大小写敏感的字符则用于分隔单词,像空格符和数字等
都是非大小写敏感的(也就是没有大小写的),它们就可以用来分隔单词。
例如:'Hello World123Android'就是标题样式的字符串,该字符串中的空格符和数字123,将其分隔为
Hello,World及Android三个单词,每个单词都是以大写字母开头,单词的其余部分为小写字母,因此,
'Hello World123Android'.istitle()在执行时,就会返回True 。
 
S.isupper()
如果S中所有大小写敏感的字符都是大写的话(S中必须至少包含一个大小写敏感的字符),该方法
就返回True,否则返回False 。
 
S.join(iterable)
将iterable(可迭代的集合,如列表等)里的所有字符串成员连接在一起,构成一个新的字符串进行返回,
字符串成员之间通过S字符串来作为分隔符。
例如:'--'.join(['aa','bb','cc','ddd'])语句执行后,返回的结果就是:'aa--bb--cc--ddd'
 
len(object)
该函数并非字符串对象的方法,它是属于内建模块里的函数。当对字符串对象执行该函数时,就可以
返回字符串里的字符个数。例如:len('hello')执行的结果就是5,也就是'hello'字符串里包含5个字符。
 
S.ljust(width[, fillchar])
当ljust方法的width参数小于等于S的字符个数时,就直接将S返回。
当width参数大于S的字符个数时,就会创建一个S的copy(拷贝),
并在copy字符串的右侧填充fillchar字符,如果fillchar没提供的话,
默认就使用空格符来填充,通过右侧填充让copy字符串能进行左对齐。
最后将这个copy字符串对象返回。
 
S.lower()
该方法会创建一个S的copy(拷贝),同时将copy字符串里的所有大写字母都转为小写字母。
最后将该copy字符串对象返回。
 
S.lstrip([chars])
该方法会创建一个S的copy(拷贝),如果没提供chars参数的话,就将copy字符串左侧的
whitespace(空白符)都移除掉,如果提供了chars参数的话,则将copy字符串左侧的所有
存在于chars里的字符都移除掉。
例如:'++++----*****////***hello'.lstrip('+-*/') 执行的结果就是:'hello' ,lstrip方法将左侧的
+ - * / 字符都移除掉了。
 
maketrans(frm, to)
maketrans是string模块里的方法,使用前需要先导入该模块,该方法会返回一个包含256个
字符的字符串(相当于一个重新设定过的ASCII码表),该字符串可以作为字符串对象的translate
方法的参数,translate方法会根据这256个字符作为ASCII码表,然后将字符串里的字符转译为
别的字符,你可以将原始的字符串看成密文,将新的ASCII码表看成密码字典,将转译后的字符串
看成是明文。maketrans方法就是创建密码字典用的。下面会举例说明。
 
max(str)
max是内建模块里的函数,当对字符串对象使用max方法时,该方法会将字符串里的ASCII码值最大的字符
进行返回。例如:max('abcd')返回的结果就是'd'
 
min(str)
min也是内建模块里的函数,当对字符串对象使用min方法时,该方法会将字符串里的ASCII码值最小的字符
进行返回。例如:min('abcd')返回的结果就是'a'
 
S.replace(old, new[, count])
该方法会创建S的一个copy(拷贝),同时将copy字符串里的old子字符串都替换为new字符串。
如果没提供count参数,则全部都替换掉,如果提供了count参数,则只替换前count个old子字符串。
例1:'is is is'.replace('is','mn') 执行后,得到的结果就是:'mn mn mn'
例2:'is is is'.replace('is','mn', 2) 执行后的结果就是:'mn mn is'
 
S.rfind(sub [,start [,end]])
rfind方法也是在S[start:end]里查找sub子字符串,与find方法所不同的是:rfind是从后往前反向进行查找。
如果找到了sub则返回sub在S里的偏移值,如果没找到,则返回-1 。
 
S.rindex(sub [,start [,end]])
类似于rfind方法,也是在S[start:end]里查找sub子字符串,只不过当rindex方法没找到sub时,
会抛出ValueError异常,而不会像rfind那样返回-1 。
 
S.rjust(width[, fillchar])
当rjust方法的width参数小于等于S的字符个数时,就直接将S返回。
当width参数大于S的字符个数时,就会创建一个S的copy(拷贝),
并在copy字符串的左侧填充fillchar字符,如果fillchar没提供的话,
默认就使用空格符来填充,通过左侧填充让copy字符串能进行右对齐。
最后将这个copy字符串对象返回。
 
S.rstrip([chars])
该方法会创建一个S的copy(拷贝),如果没提供chars参数的话,就将copy字符串右侧的
whitespace(空白符)都移除掉,如果提供了chars参数的话,则将copy字符串右侧的所有
存在于chars里的字符都移除掉。
例如:'hello---+++'.rstrip('+-') 执行的结果就是:'hello' ,该方法将字符串右侧的
所有 + 和 - 字符都移除掉了。
 
S.split([sep [,maxsplit]])
该方法会根据sep参数,将S进行分割,分割后的子字符串会形成一个列表,该列表会作为结果返回。
如果没提供sep参数的话,则使用whitespace(空白符)来进行分割。maxsplit参数用于表示分割次数,
如果没提供maxsplit参数的话,则将所有的sep都进行分割。
例1:'aa--bb--cc--dd'.split('--') 脚本执行后会返回 ['aa', 'bb', 'cc', 'dd'] 的列表,该列表就是
用'--' 分割后所形成的。
例2:'aa \n\rbb\f\fcc\v\v\rdd'.split() 脚本执行后也会返回 ['aa', 'bb', 'cc', 'dd'] ,当没提供sep参数时,就使用
whitespace(空白符)来进行分割。
例3:'aa--bb--cc--dd'.split('--', 2) 脚本执行后返回的结果为 ['aa', 'bb', 'cc--dd'] ,由于maxsplit参数的值
为2,因此,只对前两个'--'进行了分割。
 
S.splitlines(keepends=False)
该方法会将S里的多行字符串,根据换行符进行分割,分割所形成的列表作为结果返回。
如果keepends参数为True的话(默认是False),则列表里的字符串成员会保留换行符。
例1:'hello\r\nhell\nhello'.splitlines() 执行后返回的是:['hello', 'hell', 'hello']
例2:'hello\r\nhell\nhello'.splitlines(True) 执行后返回的是:['hello\r\n', 'hell\n', 'hello']
例3:'hello\r\nhell\nhello'.splitlines(3) 返回的也是:['hello\r\n', 'hell\n', 'hello'] ,这里不为0的数字,也
会被当作True 。
 
S.startswith(prefix[, start[, end]])
该方法的start与end参数是可选的,用于检测S[start:end]字符串是否是以prefix子字符串开头的。
例1:'hello'.startswith('he') 返回的结果是:True
例2:'hello'.startswith(('xe', 'he')) 返回的结果也是True,startswith方法还可以接受元组作为参数,
用于判断字符串的开头是否是以元组里的某个字符串开头的。
 
S.strip([chars])
该方法会创建一个S的copy(拷贝),如果没提供chars参数的话,就将copy字符串左右两侧的
whitespace(空白符)都移除掉,如果提供了chars参数的话,则将copy字符串左右两侧的所有
存在于chars里的字符都移除掉。
例如:'--++hello--++'.strip('+-') 返回的结果就是:'hello' ,strip方法将字符串左右两侧的 + - 字符都
移除掉了。
 
S.swapcase()
该方法会创建一个S的copy(拷贝),同时将copy字符串中的所有原小写字母都转为对应的大写字母,
并将所有原大写字母都转为对应的小写字母。最后将copy字符串对象作为结果返回。
 
S.title()
该方法会创建一个S的copy(拷贝),同时将copy字符串转为标题样式的字符串。
例如:'hello world android'.title() 执行后,返回的结果就是:'Hello World Android' ,通过
title方法就得到了对应的标题样式的字符串(前面的istitle方法里,介绍过标题样式的字符串)。
 
S.translate(table [,deletechars])
该方法会根据table(可以由之前提到的maketrans函数生成),将字符串进行转译,如果提供了
deletechars参数,则将字符串中所有存在于deletechars里的字符都移除掉。下面会进行举例说明。
 
S.upper()
该方法会创建一个S的copy(拷贝),同时将copy字符串里的所有小写字母都转为大写字母。
最后将copy字符串对象作为结果返回。
 
S.zfill(width)
如果width参数小于等于S的字符个数的话,则将S直接作为结果返回。
如果width参数大于S的字符个数的话,则创建一个S的copy(拷贝),同时将copy字符串的左侧
用'0'字符填充。最后将copy字符串对象作为结果返回。
例1:'hello'.zfill(11) 执行后,返回的结果为:'000000hello'
例2:'+1123'.zfill(11) 执行后,返回的结果为:'+0000001123' ,如果原字符串的开头是'+'或'-'字符时,
会将'+'或'-'字符放置到填充符'0'的前面。
 
S.isdecimal()
该方法与之前的isnumeric方法一样,这里的S必须是unicode字符串。
因为isdecimal方法只存在于unicode字符串对象中。
该方法用于判断字符串里的字符是否都是DECIMAL类型,要判断一个unicode字符是否是
DECIMAL类型,是由该字符对应的_PyUnicode_TypeRecord结构
(该结构位于python源码的Objects/unicodectype.c文件中)的flags字段来决定的,当flags字段存在
DECIMAL_MASK二进制位时,对应的字符就是DECIMAL类型。下面会进行举例说明。
 

    上表中的大部分函数,都可以在Python源代码的Objects/stringobject.c文件里的string_methods静态数组中查看到:

static PyMethodDef
string_methods[] = {
    /* Counterparts of the obsolete stropmodule functions; except
       string.maketrans(). */
    {"join", (PyCFunction)string_join, METH_O, join__doc__},
    {"split", (PyCFunction)string_split, METH_VARARGS, split__doc__},
    {"rsplit", (PyCFunction)string_rsplit, METH_VARARGS, rsplit__doc__},
    {"lower", (PyCFunction)string_lower, METH_NOARGS, lower__doc__},
    {"upper", (PyCFunction)string_upper, METH_NOARGS, upper__doc__},
    {"islower", (PyCFunction)string_islower, METH_NOARGS, islower__doc__},
    {"isupper", (PyCFunction)string_isupper, METH_NOARGS, isupper__doc__},
    {"isspace", (PyCFunction)string_isspace, METH_NOARGS, isspace__doc__},
    {"isdigit", (PyCFunction)string_isdigit, METH_NOARGS, isdigit__doc__},
    {"istitle", (PyCFunction)string_istitle, METH_NOARGS, istitle__doc__},
    {"isalpha", (PyCFunction)string_isalpha, METH_NOARGS, isalpha__doc__},
    {"isalnum", (PyCFunction)string_isalnum, METH_NOARGS, isalnum__doc__},
    {"capitalize", (PyCFunction)string_capitalize, METH_NOARGS,
     capitalize__doc__},
    {"count", (PyCFunction)string_count, METH_VARARGS, count__doc__},
    {"endswith", (PyCFunction)string_endswith, METH_VARARGS,
     endswith__doc__},
    {"partition", (PyCFunction)string_partition, METH_O, partition__doc__},
    {"find", (PyCFunction)string_find, METH_VARARGS, find__doc__},
    {"index", (PyCFunction)string_index, METH_VARARGS, index__doc__},
    {"lstrip", (PyCFunction)string_lstrip, METH_VARARGS, lstrip__doc__},
    {"replace", (PyCFunction)string_replace, METH_VARARGS, replace__doc__},
    {"rfind", (PyCFunction)string_rfind, METH_VARARGS, rfind__doc__},
    {"rindex", (PyCFunction)string_rindex, METH_VARARGS, rindex__doc__},
    {"rstrip", (PyCFunction)string_rstrip, METH_VARARGS, rstrip__doc__},
    {"rpartition", (PyCFunction)string_rpartition, METH_O,
     rpartition__doc__},
    {"startswith", (PyCFunction)string_startswith, METH_VARARGS,
     startswith__doc__},
    {"strip", (PyCFunction)string_strip, METH_VARARGS, strip__doc__},
    {"swapcase", (PyCFunction)string_swapcase, METH_NOARGS,
     swapcase__doc__},
    {"translate", (PyCFunction)string_translate, METH_VARARGS,
     translate__doc__},
    {"title", (PyCFunction)string_title, METH_NOARGS, title__doc__},
    {"ljust", (PyCFunction)string_ljust, METH_VARARGS, ljust__doc__},
    {"rjust", (PyCFunction)string_rjust, METH_VARARGS, rjust__doc__},
    {"center", (PyCFunction)string_center, METH_VARARGS, center__doc__},
    {"zfill", (PyCFunction)string_zfill, METH_VARARGS, zfill__doc__},
    {"format", (PyCFunction) do_string_format, METH_VARARGS | METH_KEYWORDS, format__doc__},
    {"__format__", (PyCFunction) string__format__, METH_VARARGS, p_format__doc__},
    {"_formatter_field_name_split", (PyCFunction) formatter_field_name_split, METH_NOARGS},
    {"_formatter_parser", (PyCFunction) formatter_parser, METH_NOARGS},
    {"encode", (PyCFunction)string_encode, METH_VARARGS | METH_KEYWORDS, encode__doc__},
    {"decode", (PyCFunction)string_decode, METH_VARARGS | METH_KEYWORDS, decode__doc__},
    {"expandtabs", (PyCFunction)string_expandtabs, METH_VARARGS,
     expandtabs__doc__},
    {"splitlines", (PyCFunction)string_splitlines, METH_VARARGS,
     splitlines__doc__},
    {"__sizeof__", (PyCFunction)string_sizeof, METH_NOARGS,
     sizeof__doc__},
    {"__getnewargs__",          (PyCFunction)string_getnewargs, METH_NOARGS},
    {NULL,     NULL}                         /* sentinel */
};


    上面的string_methods静态数组中,定义了字符串对象相关的方法,以及这些方法在脚本里执行时,会调用的底层的C函数。

    在前面的函数表格里,还有一些函数(或者叫方法)只能在unicode字符串对象中使用,可以在Python源码的Objects/unicodeobject.c文件的unicode_methods静态数组中,查看到这些函数:

static PyMethodDef unicode_methods[] = {
    {"encode", (PyCFunction) unicode_encode, METH_VARARGS | METH_KEYWORDS, encode__doc__},
    {"replace", (PyCFunction) unicode_replace, METH_VARARGS, replace__doc__},
    {"split", (PyCFunction) unicode_split, METH_VARARGS, split__doc__},
    {"rsplit", (PyCFunction) unicode_rsplit, METH_VARARGS, rsplit__doc__},
    {"join", (PyCFunction) unicode_join, METH_O, join__doc__},
    {"capitalize", (PyCFunction) unicode_capitalize, METH_NOARGS, capitalize__doc__},
    {"title", (PyCFunction) unicode_title, METH_NOARGS, title__doc__},
    {"center", (PyCFunction) unicode_center, METH_VARARGS, center__doc__},
    {"count", (PyCFunction) unicode_count, METH_VARARGS, count__doc__},
    {"expandtabs", (PyCFunction) unicode_expandtabs, METH_VARARGS, expandtabs__doc__},
    {"find", (PyCFunction) unicode_find, METH_VARARGS, find__doc__},
    {"partition", (PyCFunction) unicode_partition, METH_O, partition__doc__},
    {"index", (PyCFunction) unicode_index, METH_VARARGS, index__doc__},
    {"ljust", (PyCFunction) unicode_ljust, METH_VARARGS, ljust__doc__},
    {"lower", (PyCFunction) unicode_lower, METH_NOARGS, lower__doc__},
    {"lstrip", (PyCFunction) unicode_lstrip, METH_VARARGS, lstrip__doc__},
    {"decode", (PyCFunction) unicode_decode, METH_VARARGS | METH_KEYWORDS, decode__doc__},
/*  {"maketrans", (PyCFunction) unicode_maketrans, METH_VARARGS, maketrans__doc__}, */
    {"rfind", (PyCFunction) unicode_rfind, METH_VARARGS, rfind__doc__},
    {"rindex", (PyCFunction) unicode_rindex, METH_VARARGS, rindex__doc__},
    {"rjust", (PyCFunction) unicode_rjust, METH_VARARGS, rjust__doc__},
    {"rstrip", (PyCFunction) unicode_rstrip, METH_VARARGS, rstrip__doc__},
    {"rpartition", (PyCFunction) unicode_rpartition, METH_O, rpartition__doc__},
    {"splitlines", (PyCFunction) unicode_splitlines, METH_VARARGS, splitlines__doc__},
    {"strip", (PyCFunction) unicode_strip, METH_VARARGS, strip__doc__},
    {"swapcase", (PyCFunction) unicode_swapcase, METH_NOARGS, swapcase__doc__},
    {"translate", (PyCFunction) unicode_translate, METH_O, translate__doc__},
    {"upper", (PyCFunction) unicode_upper, METH_NOARGS, upper__doc__},
    {"startswith", (PyCFunction) unicode_startswith, METH_VARARGS, startswith__doc__},
    {"endswith", (PyCFunction) unicode_endswith, METH_VARARGS, endswith__doc__},
    {"islower", (PyCFunction) unicode_islower, METH_NOARGS, islower__doc__},
    {"isupper", (PyCFunction) unicode_isupper, METH_NOARGS, isupper__doc__},
    {"istitle", (PyCFunction) unicode_istitle, METH_NOARGS, istitle__doc__},
    {"isspace", (PyCFunction) unicode_isspace, METH_NOARGS, isspace__doc__},
    {"isdecimal", (PyCFunction) unicode_isdecimal, METH_NOARGS, isdecimal__doc__},
    {"isdigit", (PyCFunction) unicode_isdigit, METH_NOARGS, isdigit__doc__},
    {"isnumeric", (PyCFunction) unicode_isnumeric, METH_NOARGS, isnumeric__doc__},
    {"isalpha", (PyCFunction) unicode_isalpha, METH_NOARGS, isalpha__doc__},
    {"isalnum", (PyCFunction) unicode_isalnum, METH_NOARGS, isalnum__doc__},
    {"zfill", (PyCFunction) unicode_zfill, METH_VARARGS, zfill__doc__},
    {"format", (PyCFunction) do_string_format, METH_VARARGS | METH_KEYWORDS, format__doc__},
    {"__format__", (PyCFunction) unicode__format__, METH_VARARGS, p_format__doc__},
    {"_formatter_field_name_split", (PyCFunction) formatter_field_name_split, METH_NOARGS},
    {"_formatter_parser", (PyCFunction) formatter_parser, METH_NOARGS},
    {"__sizeof__", (PyCFunction) unicode__sizeof__, METH_NOARGS, sizeof__doc__},
#if 0
    {"capwords", (PyCFunction) unicode_capwords, METH_NOARGS, capwords__doc__},
#endif

#if 0
    /* This one is just used for debugging the implementation. */
    {"freelistsize", (PyCFunction) free_listsize, METH_NOARGS},
#endif

    {"__getnewargs__",  (PyCFunction)unicode_getnewargs, METH_NOARGS},
    {NULL, NULL}
};		


    在unicode_methods静态数组中定义了unicode字符串对象可以使用的方法,像join之类的方法,既存在于unicode_methods静态数组里,又存在于前面提到的string_methods静态数组里,因此,普通的字符串对象与unicode字符串对象都可以使用join之类的方法。但是isnumericisdecimal则只存在于unicode_methods静态数组中,因此,只能在unicode字符串对象中使用这两个方法。

    下面将对前面函数表格里的函数,逐一进行介绍。

S.capitalize:

    从上面的string_methods静态数组里,可以看到,capitalize方法所对应的底层C函数为string_capitalize,该C函数同样定义在Objects/stringobject.c文件中:

PyDoc_STRVAR(capitalize__doc__,
"S.capitalize() -> string\n\
\n\
Return a copy of the string S with only its first character\n\
capitalized.");

static PyObject *
string_capitalize(PyStringObject *self)
{
    char *s = PyString_AS_STRING(self), *s_new;
    Py_ssize_t i, n = PyString_GET_SIZE(self);
    PyObject *newobj;

    // 通过PyString_FromStringAndSize创建一个相同尺寸的字符串对象,
    // 转换后的结果将存储在该字符串对象里。
    newobj = PyString_FromStringAndSize(NULL, n);
    if (newobj == NULL)
        return NULL;
    s_new = PyString_AsString(newobj);
    if (0 < n) {
        int c = Py_CHARMASK(*s++);
        // 如果第一个字符是小写字母,
        // 则转成大写字母。
        if (islower(c))
            *s_new = toupper(c);
        else
            *s_new = c;
        s_new++;
    }
    for (i = 1; i < n; i++) {
        int c = Py_CHARMASK(*s++);
        // 其余的字符如果是大写字母,
        // 则都转为小写字母。
        if (isupper(c))
            *s_new = tolower(c);
        else
            *s_new = c;
        s_new++;
    }
    return newobj;
}


    上面代码中的capitalize__doc__变量所对应的字符串信息,为capitalize方法的帮助信息,在python的交互式输入界面里,通过help函数就可以看到这些帮助信息。上面棕色的注释是此处额外添加的。capitalize方法会先创建一个相同尺寸的字符串对象,原字符串的第一个字符如果是小写字母,则转换为大写字母,并存储到新创建的字符串对象中。其余的字符如果是大写字母,则转为小写字母,并存储到新的字符串对象里。最后将newobj这个新的字符串对象作为结果返回。该方法的使用,如下所示:

[email protected]:~$ python
Python 2.7.8 (default, Feb 20 2015, 12:54:46) 
[GCC 4.5.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> 'hello WoRld'.capitalize()
'Hello world'
>>> help(''.capitalize)
Help on built-in function capitalize:

capitalize(...)
    S.capitalize() -> string
    
    Return a copy of the string S with only its first character
    capitalized.
lines 1-7/7 (END)

>>> quit()
[email protected]:~$ 


S.center:

    center方法对应的底层C函数为:string_center (该函数也位于Objects/stringobject.c文件里):

Py_LOCAL_INLINE(PyObject *)
pad(PyStringObject *self, Py_ssize_t left, Py_ssize_t right, char fill)
{
    PyObject *u;

    if (left < 0)
        left = 0;
    if (right < 0)
        right = 0;

    if (left == 0 && right == 0 && PyString_CheckExact(self)) {
        Py_INCREF(self);
        return (PyObject *)self;
    }

    // 根据left(左侧需要填充的字符数),right(右侧需要填充的字符数),
    // 以及self本身的字符个数,创建一个新的字符串对象。
    u = PyString_FromStringAndSize(NULL,
                                   left + PyString_GET_SIZE(self) + right);
    if (u) {
        // 如果左侧需要填充字符的话,则用memset函数来对
        // 新字符串对象的左侧进行填充。
        if (left)
            memset(PyString_AS_STRING(u), fill, left);
        // 通过Py_MEMCPY拷贝函数将self中原始的字符串数据
        // 拷贝到新的字符串对象里。
        Py_MEMCPY(PyString_AS_STRING(u) + left,
               PyString_AS_STRING(self),
               PyString_GET_SIZE(self));
        // 如果需要对右侧进行填充的话,则用memset函数
        // 对新字符串的右侧进行填充。
        if (right)
            memset(PyString_AS_STRING(u) + left + PyString_GET_SIZE(self),
               fill, right);
    }

    return u;
}
....................................................
static PyObject *
string_center(PyStringObject *self, PyObject *args)
{
    Py_ssize_t marg, left;
    Py_ssize_t width;
    // 默认的填充字符为空格符
    char fillchar = ' ';

    // 获取Python脚本提供的width和fillchar参数(其中fillchar为可选参数)
    // PyArg_ParseTuple的第二个参数中,竖线左侧的为必须提供的参数,
    // 这里为n,也就是必须提供一个int(整数参数)来作为width ,
    // 竖线右侧的为可选参数,此处为c ,表示第二个参数是可选的char(字符参数,字符就是长度为1的字符串)
    // 来作为fillchar(填充字符)
    if (!PyArg_ParseTuple(args, "n|c:center", &width, &fillchar))
        return NULL;

    // 当width小于等于self(当前方法所对应的字符串对象)
    // 的字符个数时,直接将self返回。
    if (PyString_GET_SIZE(self) >= width && PyString_CheckExact(self)) {
        Py_INCREF(self);
        return (PyObject*) self;
    }

    marg = width - PyString_GET_SIZE(self);
    left = marg / 2 + (marg & width & 1);

    // pad函数会创建一个self的copy字符串,
    // left参数表示需要在copy字符串左侧填充多少个fillchar ,
    // marg - left参数表示需要在copy字符串右侧填充多少个fillchar ,
    // 通过左右填充,让copy字符串居中对齐,最后将copy字符串返回。
    return pad(self, left, marg - left, fillchar);
}


    上面的string_center最终会通过pad函数来完成具体的填充工作。center方法的具体使用,如下所示:

[email protected]:~$ python
Python 2.7.8 (default, Feb 20 2015, 12:54:46) 
[GCC 4.5.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> 'hello'.center(11)
'   hello   '
>>> 'hello'.center(11,'-')
'---hello---'
>>> 'hello'.center(11,'--')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: must be char, not str
>>> quit()
[email protected]:~$ 


    从上面的输出里可以看到,center方法的第二个参数必须是字符(也就是长度为1的字符串),如果长度超过了1,就会抛出TypeError的异常。

S.count:

    count方法对应的底层C函数为:string_count (该函数也位于Objects/stringobject.c文件里):

static PyObject *
string_count(PyStringObject *self, PyObject *args)
{
    ...............................................
    Py_ssize_t start = 0, end = PY_SSIZE_T_MAX;

    // 通过stringlib_parse_args_finds函数解析出
    // 脚本提供的sub,start和end三个参数(start与end是可选的参数)
    // stringlib_parse_args_finds函数定义于Objects/stringlib/find.h文件中。
    if (!stringlib_parse_args_finds("count", args, &sub_obj, &start, &end))
        return NULL;

    if (PyString_Check(sub_obj)) {
        sub = PyString_AS_STRING(sub_obj);
        sub_len = PyString_GET_SIZE(sub_obj);
    }
    ...............................................

    // 对start,end进行调整,比如没提供end时,
    // end就会是默认的PY_SSIZE_T_MAX,这是一个很大的数
    // ADJUST_INDICES宏就会将end调整为self本身的字符个数。
    // ADJUST_INDICES宏也定义在Objects/stringlib/find.h文件中。
    ADJUST_INDICES(start, end, PyString_GET_SIZE(self));

    // 通过stringlib_count在以str + start为起点的,
    // 以end - start为长度的字符串中,统计sub子字符串的个数。
    // stringlib_count函数定义在Objects/stringlib/count.h文件里。
    // str为self字符串对象的字符串指针
    return PyInt_FromSsize_t(
        stringlib_count(str + start, end - start, sub, sub_len, PY_SSIZE_T_MAX)
        );
}


    count方法的具体使用,如下所示:

[email protected]:~$ python
Python 2.7.8 (default, Feb 20 2015, 12:54:46) 
[GCC 4.5.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> 'hello hello hello'.count('he')
3
>>> 'hello hello hello'.count('he', 2)
2
>>> 'hello hello hello'.count('he', 2, 8)
1
>>> 'hello hello hello'.count('he', -5, -3)
1
>>> quit()
[email protected]:~$ 


    可以看到,count方法的start与end参数,还可以是负数。当为负数时,会通过前面string_count函数里的ADJUST_INDICES宏来进行调整,该宏定义在Objects/stringlib/find.h的文件中:

/* helper macro to fixup start/end slice values */
#define ADJUST_INDICES(start, end, len)         \
    if (end > len)                              \
        end = len;                              \
    else if (end < 0) {                         \
        end += len;                             \
        if (end < 0)                            \
            end = 0;                            \
    }                                           \
    if (start < 0) {                            \
        start += len;                           \
        if (start < 0)                          \
            start = 0;                          \
    }


    当end和start小于0时,就会将end和start分别加上len(字符串的字符个数),来得到有效的start与end值,因此,前面例子中的'hello hello hello'.count('he', -5, -3)其实就相当于'hello hello hello'.count('he', 12, 14) 。

S.decode与S.encode:

    在作者的系统中,和编解码相关的脚本文件位于/usr/local/lib/python2.7/encodings目录下:

[email protected]:~$ ls /usr/local/lib/python2.7/encodings/
.....................................................
ascii.py          cp875.py             koi8_u.py
ascii.pyc         cp875.pyc            koi8_u.pyc
ascii.pyo         cp875.pyo            koi8_u.pyo
base64_codec.py   cp932.py             latin_1.py
base64_codec.pyc  cp932.pyc            latin_1.pyc
.....................................................
cp1255.py         __init__.py          ptcp154.py
cp1255.pyc        __init__.pyc         ptcp154.pyc
cp1255.pyo        __init__.pyo         ptcp154.pyo
.....................................................
[email protected]:~$ 


    当python对编码进行初始化时,会先去加载执行上面的__init__.py脚本文件,该文件的内容如下:

....................................................
import codecs
from encodings import aliases
import __builtin__

_cache = {}
....................................................
def search_function(encoding):
    .................................................

# Register the search_function in the Python codec registry
codecs.register(search_function)


    在该脚本的最后,会通过codecs模块里的register函数,将search_function注册为编解码时的搜索函数。例如,当第一次对base64进行编解码时,通过search_function,就可以将对应的base64_codec.py脚本文件给加载进来,该文件的内容如下(也位于/usr/local/lib/python2.7/encodings目录中):

...................................................
import codecs, base64

### Codec APIs

def base64_encode(input,errors='strict'):

    ...................................................
    assert errors == 'strict'
    output = base64.encodestring(input)
    return (output, len(input))

def base64_decode(input,errors='strict'):

    ...................................................
    assert errors == 'strict'
    output = base64.decodestring(input)
    return (output, len(input))

...................................................

def getregentry():
    return codecs.CodecInfo(
        name='base64',
        encode=base64_encode,
        decode=base64_decode,
        incrementalencoder=IncrementalEncoder,
        incrementaldecoder=IncrementalDecoder,
        streamwriter=StreamWriter,
        streamreader=StreamReader,
    )


    在前面的search_function导入了该脚本后,就会调用该脚本里的getregentry()函数,该函数会返回一个CodecInfo对象,该对象的encode与decode属性里就有对应的编解码方法(此处为base64_encodebase64_decode)。当对字符串进行base64编码时,就会调用base64_encode方法来完成编码操作。当对字符串进行base64解码时,就会调用base64_decode方法来完成解码操作。

    search_function在第一次获取到了编码对应的CodecInfo对象后,编码与对应的CodecInfo对象就会被缓存到Python内部的一个词典中。以后就可以直接从缓存词典里,将编码对应的CodecInfo对象直接读取出来了,最后由CodecInfo对象中的encode与decode方法,去执行具体的编解码操作。

    以上就是Python编解码的大致过程,下面是字符串对象的encode方法与decode方法的简单例子:

[email protected]:~$ python
Python 2.7.8 (default, Feb 20 2015, 12:54:46) 
[GCC 4.5.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> 'hello'.encode('base64')
'aGVsbG8=\n'
>>> 'aGVsbG8=\n'.decode('base64')
'hello'
>>> 'hello'.encode('zlib')
'x\x9c\xcbH\xcd\xc9\xc9\x07\x00\x06,\x02\x15'
>>> 'x\x9c\xcbH\xcd\xc9\xc9\x07\x00\x06,\x02\x15'.decode('zlib')
'hello'
>>> 'x\x9c\xcbH\xcd\xc9\xc9\x07\x00\x06,\x02\x15'.decode('zip')
'hello'
>>> quit()
[email protected]:~$ 


    上面对'hello'字符串分别进行了base64及zlib的编解码操作,zlib和zip是相同的编码。在上面提到的encodings目录内,有一个aliases.py文件,该文件里定义了编码对应的别名,search_function在加载编码所对应的脚本文件时,是根据别名来确定脚本文件名的,aliases.py的文件内容如下:

...................................................
aliases = {
    .................................................
    # base64_codec codec
    'base64'             : 'base64_codec',
    'base_64'            : 'base64_codec',
    .................................................
    # utf_8 codec
    'u8'                 : 'utf_8',
    'utf'                : 'utf_8',
    'utf8'               : 'utf_8',
    'utf8_ucs2'          : 'utf_8',
    'utf8_ucs4'          : 'utf_8',

    # uu_codec codec
    'uu'                 : 'uu_codec',

    # zlib_codec codec
    'zip'                : 'zlib_codec',
    'zlib'               : 'zlib_codec',

}


    上面base64编码的别名为base64_codec,因此base64对应的编解码相关的脚本文件名就是base64_codec.py。此外,base_64对应的别名也是base64_codec,因此,在执行编解码方法时,使用base64与base_64的编码名,得到的结果都是一样的(其他的utf8,zip,zlib之类的编码也是同理):

[email protected]:~$ python
Python 2.7.8 (default, Feb 20 2015, 12:54:46) 
[GCC 4.5.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> 'hello'.encode('base64')
'aGVsbG8=\n'
>>> 'hello'.encode('base_64')
'aGVsbG8=\n'
>>> u'hello'.encode('u8')
'hello'
>>> u'hello'.encode('utf')
'hello'
>>> u'hello'.encode('utf8')
'hello'
>>> u'hello'.encode('utf8_ucs2')
'hello'
>>> u'hello'.encode('utf8_ucs4')
'hello'
>>> 'hello'.encode('uu')
'begin 666 <data>\n%:&5L;&\\ \n \nend\n'
>>> 'begin 666 <data>\n%:&5L;&\\ \n \nend\n'.decode('uu')
'hello'
>>> 'hello'.encode('zip')
'x\x9c\xcbH\xcd\xc9\xc9\x07\x00\x06,\x02\x15'
>>> 'hello'.encode('zlib')
'x\x9c\xcbH\xcd\xc9\xc9\x07\x00\x06,\x02\x15'
>>> quit()
[email protected]:~$ 


    可以看到,base64base_64都是base64编码,u8utfutf8utf8_ucs2utf8_ucs4都是utf-8编码,zipzlib则都是zlib编码。

S.startswith与S.endswith:

    字符串对象的startswith方法与endswith方法所对应的底层C函数为:string_startswithstring_endswith (这两个函数都定义在Objects/stringobject.c文件中):

Py_LOCAL(int)
_string_tailmatch(PyStringObject *self, PyObject *substr, Py_ssize_t start,
                  Py_ssize_t end, int direction)
{
    Py_ssize_t len = PyString_GET_SIZE(self);
    Py_ssize_t slen;
    const char* sub;
    const char* str;

    // 获取需要进行匹配的substr字符串对象的
    // 数据指针和数据长度。
    if (PyString_Check(substr)) {
        sub = PyString_AS_STRING(substr);
        slen = PyString_GET_SIZE(substr);
    }
    ................................................
    // 获取self主体字符串对象的数据指针。
    str = PyString_AS_STRING(self);

    // 通过ADJUST_INDICES宏对start,end的值进行调整,
    // 让start起始偏移值与end结束偏移值位于有效的范围内。
    ADJUST_INDICES(start, end, len);

    // 当该函数的最后一个参数direction小于0时,
    // (主要用于startswith方法)
    // start起始位置就不做调整,最后的memcmp函数就会在
    // 主体字符串的开头对substr进行匹配判断。
    if (direction < 0) {
        /* startswith */
        if (start+slen > len)
            return 0;
    } else {
        /* endswith */
        if (end-start < slen || start > len)
            return 0;

        // 当direction大于等于0时,
        // (主要用于endswith方法)
        // 就根据substr字符串对象的数据长度,
        // 将start调整到主体字符串的结尾位置处,
        // 此时start与end之间的字符个数刚好就是
        // slen即substr字符串对象的数据长度。
        // 最后的memcmp函数就会在新的start位置处,
        // 也就是主体字符串的结尾,
        // 对substr进行匹配判断。
        if (end-slen > start)
            start = end - slen;
    }
    if (end-start >= slen)
        return ! memcmp(str+start, sub, slen);
    return 0;
}


PyDoc_STRVAR(startswith__doc__,
"S.startswith(prefix[, start[, end]]) -> bool\n\
\n\
Return True if S starts with the specified prefix, False otherwise.\n\
With optional start, test S beginning at that position.\n\
With optional end, stop comparing S at that position.\n\
prefix can also be a tuple of strings to try.");

static PyObject *
string_startswith(PyStringObject *self, PyObject *args)
{
    Py_ssize_t start = 0;
    Py_ssize_t end = PY_SSIZE_T_MAX;
    PyObject *subobj;
    int result;

    // 从脚本中获取suffix,start与end三个参数,
    // 其中suffix参数会被设置到subobj对象里,
    // start与end参数为可选参数。
    if (!stringlib_parse_args_finds("startswith", args, &subobj, &start, &end))
        return NULL;
    // 第一个subobj参数可以是tuple元组,如果是元组,
    // 则将元组里的每个字符串依次提取出来,
    // 并通过_string_tailmatch函数来判断self[start:end]字符串
    // 是否是以元组里的这些字符串开头的。
    // 只要元组中有一个匹配,就返回True,
    // _string_tailmatch函数的最后一个参数为-1,
    // 当该参数小于0时,就会对主体字符串的开头位置
    // 进行匹配判断,实际的匹配方法,可以参考
    // 上面的_string_tailmatch函数的代码。
    if (PyTuple_Check(subobj)) {
        Py_ssize_t i;
        for (i = 0; i < PyTuple_GET_SIZE(subobj); i++) {
            result = _string_tailmatch(self,
                            PyTuple_GET_ITEM(subobj, i),
                            start, end, -1);
            if (result == -1)
                return NULL;
            else if (result) {
                Py_RETURN_TRUE;
            }
        }
        Py_RETURN_FALSE;
    }
    // 如果subobj不是元组,则直接通过
    // _string_tailmatch函数来判断self[start:end]字符串
    // 是否是以subobj字符串开头的。
    result = _string_tailmatch(self, subobj, start, end, -1);
    if (result == -1) {
        if (PyErr_ExceptionMatches(PyExc_TypeError))
            PyErr_Format(PyExc_TypeError, "startswith first arg must be str, "
                         "unicode, or tuple, not %s", Py_TYPE(subobj)->tp_name);
        return NULL;
    }
    else
        return PyBool_FromLong(result);
}


PyDoc_STRVAR(endswith__doc__,
"S.endswith(suffix[, start[, end]]) -> bool\n\
\n\
Return True if S ends with the specified suffix, False otherwise.\n\
With optional start, test S beginning at that position.\n\
With optional end, stop comparing S at that position.\n\
suffix can also be a tuple of strings to try.");

static PyObject *
string_endswith(PyStringObject *self, PyObject *args)
{
    Py_ssize_t start = 0;
    Py_ssize_t end = PY_SSIZE_T_MAX;
    PyObject *subobj;
    int result;

    // 从脚本中获取suffix,start与end三个参数,
    // 其中suffix参数会被设置到subobj对象里,
    // start与end参数为可选参数。
    if (!stringlib_parse_args_finds("endswith", args, &subobj, &start, &end))
        return NULL;
    // 第一个subobj参数可以是tuple元组,如果是元组,
    // 则将元组里的每个字符串依次提取出来,
    // 并通过_string_tailmatch函数来判断self[start:end]字符串
    // 是否是以元组里的这些字符串结尾的。
    // 只要元组中有一个匹配,就返回True,
    // _string_tailmatch函数的最后一个参数为+1,
    // 当该参数大于等于0时,就会对主体字符串的结尾位置
    // 进行匹配判断,实际的匹配方法,可以参考
    // 上面的_string_tailmatch函数的代码。
    if (PyTuple_Check(subobj)) {
        Py_ssize_t i;
        for (i = 0; i < PyTuple_GET_SIZE(subobj); i++) {
            result = _string_tailmatch(self,
                            PyTuple_GET_ITEM(subobj, i),
                            start, end, +1);
            if (result == -1)
                return NULL;
            else if (result) {
                Py_RETURN_TRUE;
            }
        }
        Py_RETURN_FALSE;
    }
    // 如果subobj不是元组,则直接通过
    // _string_tailmatch函数来判断self[start:end]字符串
    // 是否是以subobj字符串结尾的。
    result = _string_tailmatch(self, subobj, start, end, +1);
    if (result == -1) {
        if (PyErr_ExceptionMatches(PyExc_TypeError))
            PyErr_Format(PyExc_TypeError, "endswith first arg must be str, "
                         "unicode, or tuple, not %s", Py_TYPE(subobj)->tp_name);
        return NULL;
    }
    else
        return PyBool_FromLong(result);
}


    string_startswithstring_endswith函数最终都会通过_string_tailmatch函数来完成具体的匹配判断,上面代码中的startswith__doc__变量所对应的字符串信息,为startswith方法的帮助信息。而endswith__doc__变量所对应的字符串信息,则是endswith方法的帮助信息。这两个方法的具体使用,如下所示:

[email protected]:~$ python
Python 2.7.8 (default, Feb 20 2015, 12:54:46) 
[GCC 4.5.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> 'hello'.startswith(('he', 'wor'))
True
>>> 'world'.startswith(('he', 'wor'))
True
>>> 'hello world'.startswith('wor', 6)
True
>>> 'hello world'[6:].startswith('wor')
True
>>> help(''.startswith)
Help on built-in function startswith:

startswith(...)
    S.startswith(prefix[, start[, end]]) -> bool
    
    Return True if S starts with the specified prefix, False otherwise.
    With optional start, test S beginning at that position.
    With optional end, stop comparing S at that position.
    prefix can also be a tuple of strings to try.
lines 1-9/9 (END)

>>> 'hello'.endswith(('rld', 'llo'))
True
>>> 'world'.endswith(('rld', 'llo'))
True
>>> 'hello'.endswith(('rld', 'll'))
False
>>> 'hello'.endswith('llo')
True
>>> 'hello'.endswith('rld')
False
>>> 'hello'.endswith('ll', 1, 4)
True
>>> 'hello'[1:4].endswith('ll')
True
>>> help(''.endswith)
Help on built-in function endswith:

endswith(...)
    S.endswith(suffix[, start[, end]]) -> bool
    
    Return True if S ends with the specified suffix, False otherwise.
    With optional start, test S beginning at that position.
    With optional end, stop comparing S at that position.
    suffix can also be a tuple of strings to try.
lines 1-9/9 (END)

>>> quit()
[email protected]:~$ 


    可以看到,当startswith或endswith的第一个参数为元组时,只要元组中有一个字符串符合要求(也就是:主体字符串是以该子字符串开头或结尾的),那么startswith或endswith方法就会返回True,如果都不符合要求则返回False。第二个和第三个参数用于设置主体字符串的起始和结束位置,如上面的 'hello'.endswith('ll', 1, 4) 相当于 'hello'[1:4].endswith('ll') 。

S.expandtabs:

    expandtabs方法对应的底层C函数为 string_expandtabs (该函数也定义于Objects/stringobject.c文件里):

PyDoc_STRVAR(expandtabs__doc__,
"S.expandtabs([tabsize]) -> string\n\
\n\
Return a copy of S where all tab characters are expanded using spaces.\n\
If tabsize is not given, a tab size of 8 characters is assumed.");

static PyObject*
string_expandtabs(PyStringObject *self, PyObject *args)
{
    .................................................
    // 默认的tabsize值为8,即默认情况下,
    // 每8个字符为一个tab边界。
    int tabsize = 8;

    // 从脚本中获取expandtabs方法的tabsize参数。
    // 该参数是可选的,因此,如果脚本中没有提供该参数的话,
    // 就保持默认值,即上面设置过的8 。
    if (!PyArg_ParseTuple(args, "|i:expandtabs", &tabsize))
        return NULL;

    /* First pass: determine size of output string */
    .................................................

    /* Second pass: create output string and fill it */
    .................................................

    for (p = PyString_AS_STRING(self); p < e; p++) {
        // 将\t即tab制表符,根据tabsize,
        // 替换为特定数量的空格符。
        // 替换出来的空格符的数量不一定等于tabsize,
        // 它只会将\t后面的字符推到下一个tab边界去。
        // 例如: 'hello\t world',由于开头已经有了hello这5个字符了,
        // 因此\t就只会被替换为3个空格符。这里假设'hello'刚好位于
        // tab边界的起始位置处。
        if (*p == '\t') {
            if (tabsize > 0) {
                i = tabsize - (j % tabsize);
                j += i;
                while (i--) {
                    if (q >= qe)
                        goto overflow2;
                    *q++ = ' ';
                }
            }
        }
        .................................................
    }

    .................................................
}


    上面的expandtabs__doc__变量对应的字符串信息为expandtabs方法的帮助信息。从上面的棕色注释里(是此处额外添加的),可以看到该方法的详细解释。expandtabs方法的具体使用,如下所示:

[email protected]:~$ python
Python 2.7.8 (default, Feb 20 2015, 12:54:46) 
[GCC 4.5.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> 'hello\t world'.expandtabs()
'hello    world'
>>> 'hello\t world'.expandtabs(4)
'hello    world'
>>> 'hello\t world'.expandtabs(8)
'hello    world'
>>> 'hello\t world'.expandtabs(16)
'hello            world'
>>> quit()
[email protected]:~$ 


S.find,S.rfind,S.index及S.rindex:

    find,rfind,index及rindex这4个方法的底层C源码如下(下面的C函数都定义在Objects/stringobject.c文件中):

Py_LOCAL_INLINE(Py_ssize_t)
string_find_internal(PyStringObject *self, PyObject *args, int dir)
{
    ................................................
    // find,rfind,index及rindex这4个方法都有3个参数,
    // 第一个参数为需要查找的子字符串对象,
    // 第二个与第三个是可选的参数,表示需要进行查找的起始与结束位置。
    if (!stringlib_parse_args_finds("find/rfind/index/rindex",
             args, &subobj, &start, &end))
        return -2;

    if (PyString_Check(subobj)) {
        sub = PyString_AS_STRING(subobj);
        sub_len = PyString_GET_SIZE(subobj);
    }
    ................................................
    // 对于find和index方法,会通过stringlib_find_slice函数
    // 从start往end方向查找sub子字符串。
    // stringlib_find_slice函数定义在Objects/stringlib/find.h文件中
    if (dir > 0)
        return stringlib_find_slice(
            PyString_AS_STRING(self), PyString_GET_SIZE(self),
            sub, sub_len, start, end);
    // 对于rfind和rindex方法,则会通过stringlib_rfind_slice函数
    // 从end往start方向查找sub子字符串。
    // stringlib_rfind_slice函数也定义在Objects/stringlib/find.h文件中
    else
        return stringlib_rfind_slice(
            PyString_AS_STRING(self), PyString_GET_SIZE(self),
            sub, sub_len, start, end);
}

....................................................

static PyObject *
string_find(PyStringObject *self, PyObject *args)
{
    Py_ssize_t result = string_find_internal(self, args, +1);
    if (result == -2)
        return NULL;
    return PyInt_FromSsize_t(result);
}

....................................................

static PyObject *
string_index(PyStringObject *self, PyObject *args)
{
    Py_ssize_t result = string_find_internal(self, args, +1);
    if (result == -2)
        return NULL;
    // 当index方法查找不到sub子字符串时,
    // 会抛出ValueError异常,而不会像find方法
    // 那样返回-1 。
    if (result == -1) {
        PyErr_SetString(PyExc_ValueError,
                        "substring not found");
        return NULL;
    }
    return PyInt_FromSsize_t(result);
}

....................................................

static PyObject *
string_rfind(PyStringObject *self, PyObject *args)
{
    Py_ssize_t result = string_find_internal(self, args, -1);
    if (result == -2)
        return NULL;
    return PyInt_FromSsize_t(result);
}

....................................................

static PyObject *
string_rindex(PyStringObject *self, PyObject *args)
{
    Py_ssize_t result = string_find_internal(self, args, -1);
    if (result == -2)
        return NULL;
    // 当rindex方法查找不到sub子字符串时,
    // 会抛出ValueError异常,而不会像rfind方法
    // 那样返回-1 。
    if (result == -1) {
        PyErr_SetString(PyExc_ValueError,
                        "substring not found");
        return NULL;
    }
    return PyInt_FromSsize_t(result);
}


    上面代码中的string_findstring_indexstring_rfindstring_rindex这4个C函数,分别是find、index、rfind及rindex方法的底层C函数。这几个C函数最终都会通过string_find_internal函数来执行查找工作。从上面的代码里可以看到,find与index是从前往后进行查找,而rfind与rindex则是从后往前进行查找,当查找到子字符串后,就会将子字符串在主体字符串中的起始偏移值返回。如果找不到子字符串的话,find与rfind方法会直接将-1值返回,而index和rindex方法则会抛出ValueError的异常。

    这4个方法的具体使用,如下所示:

[email protected]:~$ python
Python 2.7.8 (default, Feb 20 2015, 12:54:46) 
[GCC 4.5.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> 'hello hello'.find('he')
0
>>> 'hello hello'.rfind('he')
6
>>> 'hello hello'.index('he')
0
>>> 'hello hello'.rindex('he')
6
>>> 'hello hello'.find('hex')
-1
>>> 'hello hello'.rfind('hex')
-1
>>> 'hello hello'.index('hex')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: substring not found
>>> 'hello hello'.rindex('hex')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: substring not found
>>> 'hello hello'.find('he', 2)
6
>>> 'hello hello'.rfind('he', 0, 5)
0
>>> 'hello hello'[2:].find('he')
4
>>> 'hello hello'[0:5].rfind('he')
0
>>> quit()
[email protected]:~$ 


    上面示例中,需要注意的地方是:虽然'hello hello'.find('he', 2)相当于在'hello hello'[2:]的字符串片段里进行查找工作,但是它返回的会是'hello hello'主体字符串中的偏移值,而非'hello hello'[2:]字符串片段中的偏移值,除非查找的起始位置为0,如上面的'hello hello'.rfind('he', 0, 5)与'hello hello'[0:5].rfind('he')得到的结果是一样的。

S.isalnum,S.isalpha及S.isdigit:

    isalnum,isalpha及isdigit这3个方法的底层C源码如下(下面的C函数都定义在Objects/stringobject.c文件中):

static PyObject*
string_isalpha(PyStringObject *self)
{
    register const unsigned char *p
        = (unsigned char *) PyString_AS_STRING(self);
    register const unsigned char *e;

    // 当字符串中只包含一个字符,
    // 且该字符为字母时,就返回True
    // PyBool_FromLong定义在Objects/boolobject.c文件中,
    // 当PyBool_FromLong的参数不为0时,就返回True对象。
    // 当PyBool_FromLong的参数为0时,就返回False对象。
    /* Shortcut for single character strings */
    if (PyString_GET_SIZE(self) == 1 &&
        isalpha(*p))
        return PyBool_FromLong(1);

    // 对于空字符串(字符个数为0的字符串),
    // 直接返回False
    /* Special case for empty strings */
    if (PyString_GET_SIZE(self) == 0)
        return PyBool_FromLong(0);

    e = p + PyString_GET_SIZE(self);
    // 循环通过libc.so(C标准库)里的
    // isalpha函数来判断字符串中的字符是否是字母,
    // 如果所有的字符都是字母时,就返回True,
    // 否则返回False
    for (; p < e; p++) {
        if (!isalpha(*p))
            return PyBool_FromLong(0);
    }
    return PyBool_FromLong(1);
}

....................................................

static PyObject*
string_isalnum(PyStringObject *self)
{
    register const unsigned char *p
        = (unsigned char *) PyString_AS_STRING(self);
    register const unsigned char *e;

    // 当字符串中只包含一个字符,
    // 且该字符为字母或数字时,就返回True
    /* Shortcut for single character strings */
    if (PyString_GET_SIZE(self) == 1 &&
        isalnum(*p))
        return PyBool_FromLong(1);

    // 对于空字符串直接返回False
    /* Special case for empty strings */
    if (PyString_GET_SIZE(self) == 0)
        return PyBool_FromLong(0);

    e = p + PyString_GET_SIZE(self);
    // 循环通过libc.so(C标准库)里的
    // isalnum函数来判断字符串中的字符是否是字母或数字,
    // 如果所有的字符都是字母或数字时,就返回True,
    // 否则返回False
    for (; p < e; p++) {
        if (!isalnum(*p))
            return PyBool_FromLong(0);
    }
    return PyBool_FromLong(1);
}

....................................................

static PyObject*
string_isdigit(PyStringObject *self)
{
    register const unsigned char *p
        = (unsigned char *) PyString_AS_STRING(self);
    register const unsigned char *e;

    // 当字符串中只包含一个字符,
    // 且该字符为0到9的数字时,就返回True
    /* Shortcut for single character strings */
    if (PyString_GET_SIZE(self) == 1 &&
        isdigit(*p))
        return PyBool_FromLong(1);

    // 对于空字符串直接返回False
    /* Special case for empty strings */
    if (PyString_GET_SIZE(self) == 0)
        return PyBool_FromLong(0);

    e = p + PyString_GET_SIZE(self);
    // 循环通过libc.so(C标准库)里的
    // isdigit函数来判断字符串中的字符是否是数字,
    // 如果所有的字符都是数字时,就返回True,
    // 否则返回False
    for (; p < e; p++) {
        if (!isdigit(*p))
            return PyBool_FromLong(0);
    }
    return PyBool_FromLong(1);
}


    从上面代码中可以看到:isalnum,isalpha及isdigit这3个方法,最终都会通过同名的C标准库函数来完成检测工作。这3个方法的具体使用,如下所示:

[email protected]:~$ python
Python 2.7.8 (default, Feb 20 2015, 12:54:46) 
[GCC 4.5.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> 'hello'.isalpha()
True
>>> 'hello123'.isalpha()
False
>>> '0123456'.isalpha()
False
>>> ''.isalpha()
False
>>> 'hello'.isalnum()
True
>>> 'hello12345'.isalnum()
True
>>> '0123456'.isalnum()
True
>>> '0123456'.isdigit()
True
>>> '0123456hello'.isdigit()
False
>>> quit()
[email protected]:~$ 


S.islower与S.isupper:

    islower及isupper这两个方法的底层C源码如下(下面的C函数都定义在Objects/stringobject.c文件中):

static PyObject*
string_islower(PyStringObject *self)
{
    register const unsigned char *p
        = (unsigned char *) PyString_AS_STRING(self);
    register const unsigned char *e;
    int cased;

    // 当字符串中只有一个字符时,
    // 如果这个字符为小写字母,就返回True,
    // 否则返回False
    /* Shortcut for single character strings */
    if (PyString_GET_SIZE(self) == 1)
        return PyBool_FromLong(islower(*p) != 0);

    // 空字符串直接返回False
    /* Special case for empty strings */
    if (PyString_GET_SIZE(self) == 0)
        return PyBool_FromLong(0);

    e = p + PyString_GET_SIZE(self);
    // cased变量是用于判断字符串中是否存在小写字母的,
    // 当字符串中至少存在一个小写字母时,
    // cased变量就会被设置为1,
    // 因此,islower方法并不要求所有的字符都是小写字母,
    // 它只要求字符串中至少有一个小写字母就可以了。
    cased = 0;
    for (; p < e; p++) {
        // 如果字符串中存在大写字母的话,
        // 则直接返回False
        if (isupper(*p))
            return PyBool_FromLong(0);
        // 只要字符串中存在一个小写字母,
        // cased的值就会变为1
        else if (!cased && islower(*p))
            cased = 1;
    }
    // 当cased为1时,PyBool_FromLong函数会返回True对象
    // 当cased为0时,PyBool_FromLong函数会返回False对象
    return PyBool_FromLong(cased);
}

....................................................

static PyObject*
string_isupper(PyStringObject *self)
{
    register const unsigned char *p
        = (unsigned char *) PyString_AS_STRING(self);
    register const unsigned char *e;
    int cased;

    // 当字符串中只有一个字符时,
    // 如果这个字符为大写字母,就返回True,
    // 否则返回False
    /* Shortcut for single character strings */
    if (PyString_GET_SIZE(self) == 1)
        return PyBool_FromLong(isupper(*p) != 0);

    // 空字符串直接返回False
    /* Special case for empty strings */
    if (PyString_GET_SIZE(self) == 0)
        return PyBool_FromLong(0);

    e = p + PyString_GET_SIZE(self);
    // cased变量是用于判断字符串中是否存在大写字母的,
    // 当字符串中至少存在一个大写字母时,
    // cased变量就会被设置为1,
    // 因此,isupper方法并不要求所有的字符都是大写字母,
    // 它只要求字符串中至少有一个大写字母就可以了。
    cased = 0;
    for (; p < e; p++) {
        // 如果字符串中存在小写字母的话,
        // 则直接返回False
        if (islower(*p))
            return PyBool_FromLong(0);
        // 只要字符串中存在一个大写字母,
        // cased的值就会变为1
        else if (!cased && isupper(*p))
            cased = 1;
    }
    // 当cased为1时,PyBool_FromLong函数会返回True对象
    // 当cased为0时,PyBool_FromLong函数会返回False对象
    return PyBool_FromLong(cased);
}


    上面代码中的string_islowerstring_isupper分别是islower及isupper方法的底层C函数。从这两个函数中可以看到:对于islower方法,当字符串中存在大小写敏感的字符时,且这些大小写敏感的字符都是小写字母时,就会返回True,否则返回False。对于isupper方法,只要存在大小写敏感的字符,且这些大小写敏感的字符都是大写字母时,就返回True,否则返回False。因此,这两个方法并不要求所有的字符都是大写或小写字母。islower与isupper方法的具体使用,如下所示:

[email protected]:~$ python
Python 2.7.8 (default, Feb 20 2015, 12:54:46) 
[GCC 4.5.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> 'hello world!!!~~(^_^)~~'.islower()
True
>>> 'HELLO WORLD!!!~~(^_^)~~'.isupper()
True
>>> 'hello World'.islower()
False
>>> 'hello World'.isupper()
False
>>> '!!!~~(^_^)~~'.islower()
False
>>> '!!!~~(^_^)~~'.isupper()
False
>>> quit()
[email protected]:~$ 


S.isnumeric与S.isdecimal:

    isnumeric与isdecimal方法都必须用于unicode字符串对象,原因在前面已经解释过了。在Python中,每个unicode字符都对应有一个_PyUnicode_TypeRecord的C结构体,该结构体定义在Objects/unicodectype.c文件里:

....................................................
#define ALPHA_MASK 0x01
#define DECIMAL_MASK 0x02
#define DIGIT_MASK 0x04
#define LOWER_MASK 0x08
#define LINEBREAK_MASK 0x10
#define SPACE_MASK 0x20
#define TITLE_MASK 0x40
#define UPPER_MASK 0x80
#define NODELTA_MASK 0x100
#define NUMERIC_MASK 0x200

typedef struct {
    const Py_UNICODE upper;
    const Py_UNICODE lower;
    const Py_UNICODE title;
    const unsigned char decimal;
    const unsigned char digit;
    const unsigned short flags;
} _PyUnicode_TypeRecord;

#include "unicodetype_db.h"
....................................................


    在上面的_PyUnicode_TypeRecord结构体中,有一个flags字段,当该字段里存在NUMERIC_MASK二进制位时,对应的unicode字符就是NUMERIC类型。当flags字段里存在DECIMAL_MASK二进制位时,对应的unicode字符就是DECIMAL类型。所有unicode字符的_PyUnicode_TypeRecord结构,都存储在Objects/unicodetype_db.h头文件里的_PyUnicode_TypeRecords数组中:

/* this file was generated by Tools/unicode/makeunicodedata.py 2.6 */

/* a list of unique character type descriptors */
const _PyUnicode_TypeRecord _PyUnicode_TypeRecords[] = {
    {0, 0, 0, 0, 0, 0},
    {0, 0, 0, 0, 0, 0},
    {0, 0, 0, 0, 0, 32},
    {0, 0, 0, 0, 0, 48},
    {0, 0, 0, 0, 0, 518},
    {0, 0, 0, 1, 1, 518},
    {0, 0, 0, 2, 2, 518},
    {0, 0, 0, 3, 3, 518},
    {0, 0, 0, 4, 4, 518},
    {0, 0, 0, 5, 5, 518},
    {0, 0, 0, 6, 6, 518},
    {0, 0, 0, 7, 7, 518},
    {0, 0, 0, 8, 8, 518},
    {0, 0, 0, 9, 9, 518},
    ................................................
};
....................................................


    上面代码中的09的unicode字符,所对应的flags字段的值为518(即0x206),因此,该字段的NUMERIC_MASK(0x200),DIGIT_MASK(0x04)及DECIMAL_MASK(0x02)这3个二进制位都是1,所以,这10个字符既是NUMERIC类型,也是DECIMAL类型,同时还是DIGIT类型。这里要介绍的isnumeric与isdecimal方法,就是根据这些类型来对unicode字符进行检测的。

    isnumeric与isdecimal方法所对应的底层C函数如下(这些C函数定义在Objects/unicodeobject.c文件中):

static PyObject*
unicode_isdecimal(PyUnicodeObject *self)
{
    register const Py_UNICODE *p = PyUnicode_AS_UNICODE(self);
    register const Py_UNICODE *e;

    // 当unicode字符串中只包含一个字符时,
    // 如果这个字符是DECIMAL类型,那么就返回True
    /* Shortcut for single character strings */
    if (PyUnicode_GET_SIZE(self) == 1 &&
        Py_UNICODE_ISDECIMAL(*p))
        return PyBool_FromLong(1);

    // 空字符串直接返回False
    /* Special case for empty strings */
    if (PyUnicode_GET_SIZE(self) == 0)
        return PyBool_FromLong(0);

    e = p + PyUnicode_GET_SIZE(self);
    // 如果字符串里的字符都是DECIMAL类型,
    // 就返回True,否则返回False
    for (; p < e; p++) {
        if (!Py_UNICODE_ISDECIMAL(*p))
            return PyBool_FromLong(0);
    }
    return PyBool_FromLong(1);
}

....................................................

static PyObject*
unicode_isnumeric(PyUnicodeObject *self)
{
    register const Py_UNICODE *p = PyUnicode_AS_UNICODE(self);
    register const Py_UNICODE *e;

    // 当unicode字符串中只包含一个字符时,
    // 如果这个字符是NUMERIC类型,那么就返回True
    /* Shortcut for single character strings */
    if (PyUnicode_GET_SIZE(self) == 1 &&
        Py_UNICODE_ISNUMERIC(*p))
        return PyBool_FromLong(1);

    // 空字符串直接返回False
    /* Special case for empty strings */
    if (PyUnicode_GET_SIZE(self) == 0)
        return PyBool_FromLong(0);

    e = p + PyUnicode_GET_SIZE(self);
    // 如果字符串里的字符都是NUMERIC类型,
    // 就返回True,否则返回False
    for (; p < e; p++) {
        if (!Py_UNICODE_ISNUMERIC(*p))
            return PyBool_FromLong(0);
    }
    return PyBool_FromLong(1);
}


    上面的unicode_isdecimalunicode_isnumeric分别为isdecimal和isnumeric方法的底层C函数。这两个方法的具体使用,如下所示:

[email protected]:~$ python
Python 2.7.8 (default, Feb 20 2015, 12:54:46) 
[GCC 4.5.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> u'0123456789'.isnumeric()
True
>>> u'零一二三四五六七八九'.isnumeric()
True
>>> u'0123456789'.isdecimal()
True
>>> u'零一二三四五六七八九'.isdecimal()
False
>>> for i in range(65535):
...   if(unichr(i).isnumeric()):
...     print '%#x' % i
...     print u'%c' % unichr(i)
... 
0x30
0
0x31
1
0x32
2
0x33
3
0x34
4
0x35
5
.................... // 省略掉N行输出信息
>>> for i in range(65535):
...   if(unichr(i).isdecimal()):
...     print '%#x' % i
...     print u'%c' % unichr(i)
... 
0x30
0
0x31
1
0x32
2
0x33
3
0x34
4
0x35
5
.................... // 省略掉N行输出信息
>>> quit()
[email protected]:~$ 


    你可以像上面那样,通过for循环来简单的浏览一下,哪些unicode字符是NUMERIC类型,哪些是DECIMAL类型。从作者实际的for循环的输出情况来看,NUMERIC类型的字符还是很多的,像'零','一','二'之类的中文数字,以及罗马数字等都属于NUMERIC类型。DECIMAL类型的字符则相对少点。

S.isspace:

    isspace方法相关的底层C函数如下(该C函数定义在Objects/stringobject.c文件里):

static PyObject*
string_isspace(PyStringObject *self)
{
    register const unsigned char *p
        = (unsigned char *) PyString_AS_STRING(self);
    register const unsigned char *e;

    // 当字符串中只包含一个字符,
    // 且该字符为空白字符时,就返回True
    // 空白符可以是空格符,\f(换页符),
    // \n(换行符),\r(回车符),\t(水平制表符),
    // 以及\v(垂直制表符)
    /* Shortcut for single character strings */
    if (PyString_GET_SIZE(self) == 1 &&
        isspace(*p))
        return PyBool_FromLong(1);

    // 对于空字符串直接返回False
    /* Special case for empty strings */
    if (PyString_GET_SIZE(self) == 0)
        return PyBool_FromLong(0);

    e = p + PyString_GET_SIZE(self);
    // 循环通过libc.so(C标准库)里的
    // isspace函数来判断字符串中的字符是否是空白字符,
    // 如果所有的字符都是空白字符时,就返回True,
    // 否则返回False
    for (; p < e; p++) {
        if (!isspace(*p))
            return PyBool_FromLong(0);
    }
    return PyBool_FromLong(1);
}


    isspace方法的具体使用,如下所示:

[email protected]:~$ python
Python 2.7.8 (default, Feb 20 2015, 12:54:46) 
[GCC 4.5.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> ' \r\n\v\f\t'.isspace()
True
>>> 'hello'.isspace()
False
>>> quit()
[email protected]:~$ 


S.istitle:

    istitle方法相关的底层C函数如下(也定义在Objects/stringobject.c文件中):

static PyObject*
string_istitle(PyStringObject *self, PyObject *uncased)
{
    register const unsigned char *p
        = (unsigned char *) PyString_AS_STRING(self);
    register const unsigned char *e;
    int cased, previous_is_cased;

    // 当字符串中只包含一个字符,
    // 且该字符为大写字母时,就返回True
    /* Shortcut for single character strings */
    if (PyString_GET_SIZE(self) == 1)
        return PyBool_FromLong(isupper(*p) != 0);

    // 对于空字符串,直接返回False
    /* Special case for empty strings */
    if (PyString_GET_SIZE(self) == 0)
        return PyBool_FromLong(0);

    e = p + PyString_GET_SIZE(self);
    // cased变量用于判断字符串中,
    // 是否存在大小写敏感的字符。
    // 如果没有大小写敏感的字符,
    // 将返回False
    cased = 0;
    // previous_is_cased变量用于判断
    // 当前的字母是否是单词的首字母。
    previous_is_cased = 0;
    for (; p < e; p++) {
        register const unsigned char ch = *p;

        // 每个单词的首字母必须是大写字母。
        if (isupper(ch)) {
            if (previous_is_cased)
                return PyBool_FromLong(0);
            previous_is_cased = 1;
            cased = 1;
        }
        // 每个单词的除首字母以外的其他字母
        // 则必须是小写字母。
        else if (islower(ch)) {
            if (!previous_is_cased)
                return PyBool_FromLong(0);
            previous_is_cased = 1;
            cased = 1;
        }
        // 非大小写敏感的字符则用于分隔单词,
        // 通过将previous_is_cased重置为0,
        // 从而可以让下一个大小写敏感的字符成为
        // 下一个单词的首字母。
        else
            previous_is_cased = 0;
    }
    return PyBool_FromLong(cased);
}


    istitle方法是用于判断一个字符串,是否是标题样式的。标题样式的字符串中必须包含大小写敏感的字符(也就是大写字母或小写字母),非大小写敏感的字符主要起到分隔单词的作用(例如空格符,数字等都可以将左右两侧的字母分隔为两个单词)。此外,标题样式的字符串中,每个单词的首字母必须是大写字母,单词的除首字母以外的其他字母,则必须是小写字母。具体的使用,如下所示:

[email protected]:~$ python
Python 2.7.8 (default, Feb 20 2015, 12:54:46) 
[GCC 4.5.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> 'Hello World Android123Haha'.istitle()
True
>>> 'H'.istitle()
True
>>> 'hello World'.istitle()
False
>>> 'h'.istitle()
False
>>> 'HeLlo'.istitle()
False
>>> 'Hello'.istitle()
True
>>> 'He;Lo'.istitle()
True
>>> quit()
[email protected]:~$ 


S.join:

    和join方法相关的底层C函数如下(定义于Objects/stringobject.c文件中):

static PyObject *
string_join(PyStringObject *self, PyObject *orig)
{
    // join方法的self主体字符串被用作分隔字符串
    char *sep = PyString_AS_STRING(self);
    const Py_ssize_t seplen = PyString_GET_SIZE(self);
    ................................................

    // orig是join方法的第一个参数,
    // 也就是join方法需要操作的集合
    seq = PySequence_Fast(orig, "");
    if (seq == NULL) {
        return NULL;
    }

    // 获取集合里的元素个数
    seqlen = PySequence_Size(seq);
    // 当集合中的元素个数为0,也就是空集合时,
    // 直接返回一个空字符串
    if (seqlen == 0) {
        Py_DECREF(seq);
        return PyString_FromString("");
    }
    // 当集合中只有一个元素,且该元素为
    // 字符串对象时,直接将该字符串对象返回
    if (seqlen == 1) {
        item = PySequence_Fast_GET_ITEM(seq, 0);
        if (PyString_CheckExact(item) || PyUnicode_CheckExact(item)) {
            Py_INCREF(item);
            Py_DECREF(seq);
            return item;
        }
    }

    ................................................
    for (i = 0; i < seqlen; i++) {
        const size_t old_sz = sz;
        item = PySequence_Fast_GET_ITEM(seq, i);
        // 集合里的每个元素都必须是字符串类型,
        // 否则会抛出TypeError即类型错误
        if (!PyString_Check(item)){
        ...............................................
            PyErr_Format(PyExc_TypeError,
                         "sequence item %zd: expected string,"
                         " %.80s found",
                         i, Py_TYPE(item)->tp_name);
            Py_DECREF(seq);
            return NULL;
        }
        // 将集合中每个字符串的尺寸都统计到sz变量里,
        // 同时将seplen即分隔字符串的尺寸也统计到sz中,
        // 下面会通过sz的值来创建需要返回的结果字符串对象
        sz += PyString_GET_SIZE(item);
        if (i != 0)
            sz += seplen;
        ...............................................
    }

    // 根据sz的值来创建结果字符串对象
    /* Allocate result space. */
    res = PyString_FromStringAndSize((char*)NULL, sz);
    if (res == NULL) {
        Py_DECREF(seq);
        return NULL;
    }

    /* Catenate everything. */
    p = PyString_AS_STRING(res);
    // 将集合里的每个字符串都拷贝到结果字符串中,
    // 同时将sep分隔字符串也拷贝到结果字符串里,
    // 集合的每个字符串之间通过分隔字符串隔开
    for (i = 0; i < seqlen; ++i) {
        size_t n;
        item = PySequence_Fast_GET_ITEM(seq, i);
        n = PyString_GET_SIZE(item);
        Py_MEMCPY(p, PyString_AS_STRING(item), n);
        p += n;
        if (i < seqlen - 1) {
            Py_MEMCPY(p, sep, seplen);
            p += seplen;
        }
    }

    Py_DECREF(seq);
    // 将结果字符串对象返回
    return res;
}


    join方法的具体使用,如下所示:

[email protected]:~$ python
Python 2.7.8 (default, Feb 20 2015, 12:54:46) 
[GCC 4.5.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> '--'.join([])
''
>>> '--'.join(['hello'])
'hello'
>>> '--'.join(['hello', 'world'])
'hello--world'
>>> '--'.join(['aa', 'bb', 'cc', 'dd', 'ee'])
'aa--bb--cc--dd--ee'
>>> '*-*'.join(['aa', 'bb', 'cc', 'dd', 'ee'])
'aa*-*bb*-*cc*-*dd*-*ee'
>>> '*-*'.join(['aa', 'bb', 'cc', 'dd', 123])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: sequence item 4: expected string, int found
>>> quit()
[email protected]:~$ 


    上面最后一个例子中,由于集合中的最后一个元素是整数123,不是字符串类型,因此就抛出了TypeError的类型错误。

len:

    len是属于内建模块里的函数,当对字符串对象使用len函数时,最终会通过下面的string_length这个底层C函数,来获取字符串的尺寸信息(该底层C函数也定义在Objects/stringobject.c文件中):

static Py_ssize_t
string_length(PyStringObject *a)
{
    return Py_SIZE(a);
}


    上面会通过Py_SIZE宏,来获取字符串对象所包含的字符个数。len函数的具体使用如下:

[email protected]:~$ python
Python 2.7.8 (default, Feb 20 2015, 12:54:46) 
[GCC 4.5.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> len('hello')
5
>>> len('hello world')
11
>>> quit()
[email protected]:~$


S.ljust与S.rjust:

    ljust与rjust方法所对应的底层C函数如下(定义在Objects/stringobject.c文件中):

static PyObject *
string_ljust(PyStringObject *self, PyObject *args)
{
    Py_ssize_t width;
    // 默认的填充字符为空格符
    char fillchar = ' ';

    // 从脚本中获取width宽度信息和fillchar填充字符
    // fillchar为可选参数,如果没提供的话,
    // 就使用默认的空格符
    if (!PyArg_ParseTuple(args, "n|c:ljust", &width, &fillchar))
        return NULL;

    // 当width参数小于等于self主体字符串的字符个数时,
    // 直接将self字符串对象返回
    if (PyString_GET_SIZE(self) >= width && PyString_CheckExact(self)) {
        Py_INCREF(self);
        return (PyObject*) self;
    }

    // 通过pad函数,创建一个self的copy拷贝字符串对象,
    // width - PyString_GET_SIZE(self)作为pad函数的第三个参数,表示:
    // 需要对copy字符串的右侧填充多少个fillchar字符,
    // 通过右侧填充,让copy字符串进行左对齐,
    // 最后将copy字符串对象返回。
    return pad(self, 0, width - PyString_GET_SIZE(self), fillchar);
}

....................................................

static PyObject *
string_rjust(PyStringObject *self, PyObject *args)
{
    Py_ssize_t width;
    char fillchar = ' ';

    if (!PyArg_ParseTuple(args, "n|c:rjust", &width, &fillchar))
        return NULL;

    if (PyString_GET_SIZE(self) >= width && PyString_CheckExact(self)) {
        Py_INCREF(self);
        return (PyObject*) self;
    }

    // 通过pad函数,创建一个self的copy拷贝字符串对象,
    // width - PyString_GET_SIZE(self)作为pad函数的第二个参数,表示:
    // 需要对copy字符串的左侧填充多少个fillchar字符,
    // 通过左侧填充,让copy字符串进行右对齐,
    // 最后将copy字符串对象返回。
    return pad(self, width - PyString_GET_SIZE(self), 0, fillchar);
}


    上面的pad函数在之前介绍S.center方法时,已经介绍过了。ljust方法是通过右侧填充fillchar字符来实现左对齐,而rjust方法则是通过左侧填充fillchar字符来实现右对齐。这两个方法的具体使用如下:

[email protected]:~$ python
Python 2.7.8 (default, Feb 20 2015, 12:54:46) 
[GCC 4.5.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> 'hello'.ljust(11)
'hello      '
>>> 'hello'.ljust(11, '-')
'hello------'
>>> 'hello'.ljust(3)
'hello'
>>> 'hello'.rjust(11)
'      hello'
>>> 'hello'.rjust(11, '-')
'------hello'
>>> 'hello'.rjust(3)
'hello'
>>> quit()
[email protected]:~$ 


S.lower与S.upper:

    lower与upper方法的底层C函数如下(这些C函数也定义在Objects/stringobject.c文件中):

#ifndef _tolower
#define _tolower tolower
#endif

static PyObject *
string_lower(PyStringObject *self)
{
    char *s;
    Py_ssize_t i, n = PyString_GET_SIZE(self);
    PyObject *newobj;

    // 根据self主体字符串的尺寸,
    // 创建一个新的copy字符串对象
    newobj = PyString_FromStringAndSize(NULL, n);
    if (!newobj)
        return NULL;

    // 得到copy字符串对象的字符串指针,
    // 该指针指向了具体的字符串数据
    s = PyString_AS_STRING(newobj);

    // 将原self字符串对象里的字符串数据,
    // 拷贝到新的copy字符串中
    Py_MEMCPY(s, PyString_AS_STRING(self), n);

    // 将copy字符串里的所有大写字母都转为
    // 对应的小写字母。
    for (i = 0; i < n; i++) {
        int c = Py_CHARMASK(s[i]);
        if (isupper(c))
            s[i] = _tolower(c);
    }

    return newobj;
}

....................................................

#ifndef _toupper
#define _toupper toupper
#endif

static PyObject *
string_upper(PyStringObject *self)
{
    char *s;
    Py_ssize_t i, n = PyString_GET_SIZE(self);
    PyObject *newobj;

    // 根据self主体字符串的尺寸,
    // 创建一个新的copy字符串对象
    newobj = PyString_FromStringAndSize(NULL, n);
    if (!newobj)
        return NULL;

    // 得到copy字符串对象的字符串指针,
    // 该指针指向了具体的字符串数据
    s = PyString_AS_STRING(newobj);

    // 将原self字符串对象里的字符串数据,
    // 拷贝到新的copy字符串中
    Py_MEMCPY(s, PyString_AS_STRING(self), n);

    // 将copy字符串里的所有小写字母都转为
    // 对应的大写字母。
    for (i = 0; i < n; i++) {
        int c = Py_CHARMASK(s[i]);
        if (islower(c))
            s[i] = _toupper(c);
    }

    return newobj;
}


    上面的string_lowerstring_upper,分别为lower和upper方法的底层C函数。这两个方法都会创建一个新的copy字符串对象。其中,lower方法会将copy字符串里的所有大写字母都转为小写字母,而upper方法则会将copy字符串中的所有小写字母都转为大写字母。这两个方法的具体使用如下:

[email protected]:~$ python
Python 2.7.8 (default, Feb 20 2015, 12:54:46) 
[GCC 4.5.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> 'HELLO WORLD!'.lower()
'hello world!'
>>> 'hello world!'.upper()
'HELLO WORLD!'
>>> quit()
[email protected]:~$ 


S.lstrip,S.rstrip及S.strip:

    lstrip,rstrip及strip这三个方法所对应的底层C函数如下(定义在Objects/stringobject.c文件中):

Py_LOCAL_INLINE(PyObject *)
do_xstrip(PyStringObject *self, int striptype, PyObject *sepobj)
{
    char *s = PyString_AS_STRING(self);
    Py_ssize_t len = PyString_GET_SIZE(self);
    char *sep = PyString_AS_STRING(sepobj);
    Py_ssize_t seplen = PyString_GET_SIZE(sepobj);
    Py_ssize_t i, j;

    i = 0;
    // striptype != RIGHTSTRIP表示当需要剔除左侧的字符时,或者
    // 当需要将左右两侧的字符都剔除掉时,就执行if里的循环语句。
    // sep字符串中的每个字符,都是需要剔除掉的字符,
    // s为原self字符串对象的字符串指针,
    // 循环判断self左侧的字符是否存在于sep字符串中,
    // 如果左侧的字符存在于sep里,就将i加一,也就是
    // 跳过该字符,这样就间接的剔除掉了该字符,
    // 因为i会作为最后截取字符串片段操作时的起始位置。
    // 直到self在左侧遇到一个非sep字符串中的字符时,
    // 才跳出循环
    if (striptype != RIGHTSTRIP) {
        while (i < len && memchr(sep, Py_CHARMASK(s[i]), seplen)) {
            i++;
        }
    }

    j = len;
    // 如果需要将右侧的字符给剔除掉时,
    // 就将self右侧的字符分别与sep字符串中的字符进行比较,
    // 当右侧的字符存在于sep字符串中时,就将j减一,
    // 也就是将该字符给剔除掉,因为j会作为最后截取字符串
    // 片段操作时的结束位置。
    // 直到self在右侧遇到一个非sep字符串中的字符时,才跳出循环。
    if (striptype != LEFTSTRIP) {
        do {
            j--;
        } while (j >= i && memchr(sep, Py_CHARMASK(s[j]), seplen));
        j++;
    }

    if (i == 0 && j == len && PyString_CheckExact(self)) {
        Py_INCREF(self);
        return (PyObject*)self;
    }
    else
        // 根据i和j的值,对self字符串进行截取操作。
        // 将i到j的字符串片段给截取出来
        // (当然返回的会是一个新的字符串对象),
        // 通过截取操作,原self左右两侧的需要剔除的字符,
        // 就自动被截掉了。
        return PyString_FromStringAndSize(s+i, j-i);
}

Py_LOCAL_INLINE(PyObject *)
do_strip(PyStringObject *self, int striptype)
{
    char *s = PyString_AS_STRING(self);
    Py_ssize_t len = PyString_GET_SIZE(self), i, j;

    i = 0;
    // 当需要剔除左侧的空白字符时,
    // 循环通过isspace来判断左侧是否是空白字符,
    // 如果是空白字符就将起始位置i加一,
    // isspace是C标准的库函数。
    if (striptype != RIGHTSTRIP) {
        while (i < len && isspace(Py_CHARMASK(s[i]))) {
            i++;
        }
    }

    j = len;
    // 当需要剔除右侧的空白字符时,
    // 循环通过isspace来判断右侧是否是空白字符,
    // 如果是空白字符就将结束位置j减一,
    if (striptype != LEFTSTRIP) {
        do {
            j--;
        } while (j >= i && isspace(Py_CHARMASK(s[j])));
        j++;
    }

    if (i == 0 && j == len && PyString_CheckExact(self)) {
        Py_INCREF(self);
        return (PyObject*)self;
    }
    else
        // 通过i和j来截取字符串片段,从而将
        // 左侧或右侧的空白字符给剔除掉。
        return PyString_FromStringAndSize(s+i, j-i);
}

Py_LOCAL_INLINE(PyObject *)
do_argstrip(PyStringObject *self, int striptype, PyObject *args)
{
    PyObject *sep = NULL;

    if (!PyArg_ParseTuple(args, (char *)stripformat[striptype], &sep))
        return NULL;

    if (sep != NULL && sep != Py_None) {
        // 如果提供了sep(其中包含了需要剔除的字符)时,
        // 就通过上面的do_xstrip函数,将左侧或右侧的
        // 存在于sep中的字符给剔除掉。
        // striptype的值可以是LEFTSTRIP(表示剔除掉左侧的字符),
        // RIGHTSTRIP(表示剔除掉右侧的字符)
        // 或者是BOTHSTRIP(表示剔除掉左右两侧的字符)
        if (PyString_Check(sep))
            return do_xstrip(self, striptype, sep);
    ................................................
    }

    // 如果没提供sep,则通过do_strip函数
    // 将左侧或右侧的空白字符给剔除掉。
    return do_strip(self, striptype);
}

....................................................

static PyObject *
string_strip(PyStringObject *self, PyObject *args)
{
    // 如果strip方法没提供参数的话,
    // 就通过do_strip函数将左右两侧的空白字符
    // 给剔除掉。
    if (PyTuple_GET_SIZE(args) == 0)
        return do_strip(self, BOTHSTRIP); /* Common case */
    else
    // 如果提供了参数,就通过
    // do_argstrip函数将包含在参数中的
    // 左右两侧的字符给剔除掉
        return do_argstrip(self, BOTHSTRIP, args);
}

....................................................

static PyObject *
string_lstrip(PyStringObject *self, PyObject *args)
{
    // lstrip方法就是将左侧的字符给剔除掉
    if (PyTuple_GET_SIZE(args) == 0)
        return do_strip(self, LEFTSTRIP); /* Common case */
    else
        return do_argstrip(self, LEFTSTRIP, args);
}

....................................................

static PyObject *
string_rstrip(PyStringObject *self, PyObject *args)
{
    // rstrip方法就是将右侧的字符给剔除掉
    if (PyTuple_GET_SIZE(args) == 0)
        return do_strip(self, RIGHTSTRIP); /* Common case */
    else
        return do_argstrip(self, RIGHTSTRIP, args);
}


    strip,lstrip与rstrip方法的底层C函数,分别为string_stripstring_lstripstring_rstrip。它们最终会通过do_xstrip或do_strip函数来完成具体的剔除工作。这三个方法的具体使用如下所示:

[email protected]:~$ python
Python 2.7.8 (default, Feb 20 2015, 12:54:46) 
[GCC 4.5.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> ' \r\n\f\t\v\t hello world'.lstrip()
'hello world'
>>> '--+++---****--/////hello world'.lstrip('+-*/')
'hello world'
>>> 'hello world \r\v\t\f\f\n\n   '.rstrip()
'hello world'
>>> 'hello world--+++---****--/////'.rstrip('+-*/')
'hello world'
>>> ' \r\n\f\t\v\t hello world \r\r\n\n\t\t\f\f'.strip()
'hello world'
>>> '++-----====~~hello world!!!!~~~~'.strip('-+=~!')
'hello world'
>>> quit()
[email protected]:~$ 


maketrans与S.translate:

    maketrans是定义在string模块中的函数(在作者的系统里,string模块的相关代码位于/usr/local/lib/python2.7/string.py的脚本文件中):

....................................................
l = map(chr, xrange(256))
_idmap = str('').join(l)
del l

....................................................

# Construct a translation string
_idmapL = None
def maketrans(fromstr, tostr):
    """maketrans(frm, to) -> string

    Return a translation table (a string of 256 bytes long)
    suitable for use in string.translate.  The strings frm and to
    must be of the same length.

    """
    if len(fromstr) != len(tostr):
        raise ValueError, "maketrans arguments must have same length"
    global _idmapL
    if not _idmapL:
        _idmapL = list(_idmap)
    L = _idmapL[:]
    fromstr = map(ord, fromstr)
    for i in range(len(fromstr)):
        L[fromstr[i]] = tostr[i]
    return ''.join(L)


    上面的_idmap字符串里包含了256个字符,这些字符是按照ASCII码表的顺序来排列的:

[email protected]:~$ python
Python 2.7.8 (default, Feb 20 2015, 12:54:46) 
[GCC 4.5.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import string
>>> string._idmap
'..............................................
...............................................
\x1d\x1e\x1f !"#$%&\'()*+,-./0123456789:;<=>?@
ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmn
opqrstuvwxyz{|}~...............................
...............................................
.............................................'
>>> quit()
[email protected]:~$ 


    makestrans函数其实就是将上面的ASCII码字符串做调整,如下所示:

[email protected]:~$ python
Python 2.7.8 (default, Feb 20 2015, 12:54:46) 
[GCC 4.5.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import string
>>> string._idmap
'..............................................
...............................................
\x1d\x1e\x1f !"#$%&\'()*+,-./0123456789:;<=>?@
ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmn
opqrstuvwxyz{|}~...............................
...............................................
.............................................'
>>> string.maketrans('ABCD', '1234')
'..............................................
...............................................
\x1d\x1e\x1f !"#$%&\'()*+,-./0123456789:;<=>?@
1234EFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmn
opqrstuvwxyz{|}~...............................
...............................................
...............................................'
>>> quit()
[email protected]:~$ 


    上面string模块里的maketrans函数,将原ASCII码字符串中的'ABCD'这4个字符,替换为了'1234'。

    字符串对象的translate方法,就可以使用maketrans函数所返回的字符串,来作为新的ASCII码表。从而将主体字符串里的字符做一个映射处理:

[email protected]:~$ python
Python 2.7.8 (default, Feb 20 2015, 12:54:46) 
[GCC 4.5.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import string
>>> table = string.maketrans('ABCD', '1234')
>>> table
'..............................................
...............................................
\x1d\x1e\x1f !"#$%&\'()*+,-./0123456789:;<=>?@
1234EFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmn
opqrstuvwxyz{|}~...............................
...............................................
...............................................'
>>> 'AABBCCDD hello'.translate(table)
'11223344 hello'
>>> quit()
[email protected]:~$ 


    上面字符串对象的translate方法,根据table字符串(由maketrans函数生成),将ABCD字符依次替换为1234

    字符串对象的translate方法所对应的底层C函数为string_translate(也定义在Objects/stringobject.c文件中):

PyDoc_STRVAR(translate__doc__,
"S.translate(table [,deletechars]) -> string\n\
\n\
Return a copy of the string S, where all characters occurring\n\
in the optional argument deletechars are removed, and the\n\
remaining characters have been mapped through the given\n\
translation table, which must be a string of length 256 or None.\n\
If the table argument is None, no translation is applied and\n\
the operation simply removes the characters in deletechars.");

static PyObject *
string_translate(PyStringObject *self, PyObject *args)
{
    ................................................
    // 将脚本的第一个参数设置到tableobj中,
    // 将脚本的第二个参数设置到delobj中,其中,
    // 第一个参数为必须提供的参数,
    // 第二个参数为可选参数,两个参数都必须是字符串对象,
    // delobj对象所对应的字符串中的每个字符都是需要被
    // 删除掉的字符。
    if (!PyArg_UnpackTuple(args, "translate", 1, 2,
                          &tableobj, &delobj))
        return NULL;

    // 将tableobj字符串对象的字符串指针设置到table变量,
    // 同时将tableobj字符串对象所包含的字符个数设置到tablen变量中。
    if (PyString_Check(tableobj)) {
        table = PyString_AS_STRING(tableobj);
        tablen = PyString_GET_SIZE(tableobj);
    }
    // 如果第一个参数是None的话,则将table设置为空指针。
    else if (tableobj == Py_None) {
        table = NULL;
        tablen = 256;
    }
    ................................................

    // table字符串中必须包含256个字符
    if (tablen != 256) {
        PyErr_SetString(PyExc_ValueError,
          "translation table must be 256 characters long");
        return NULL;
    }

    // 获取delobj字符串对象所对应的字符串指针与
    // 该字符串所包含的字符个数。
    if (delobj != NULL) {
        if (PyString_Check(delobj)) {
            del_table = PyString_AS_STRING(delobj);
            dellen = PyString_GET_SIZE(delobj);
        }
        .............................................
    }
    else {
        del_table = NULL;
        dellen = 0;
    }

    // 获取主体字符串的长度信息。
    inlen = PyString_GET_SIZE(input_obj);
    // 根据主体字符串的长度,
    // 来创建需要返回的result结果字符串对象。
    result = PyString_FromStringAndSize((char *)NULL, inlen);
    if (result == NULL)
        return NULL;
    // 将结果字符串对象的字符串指针设置到output变量。
    output_start = output = PyString_AsString(result);
    // 获取主体字符串对象的字符串指针。
    input = PyString_AS_STRING(input_obj);

    // 当dellen == 0,且table不为空指针时,
    // 直接根据table字符串来做映射处理。
    if (dellen == 0 && table != NULL) {
        /* If no deletions are required, use faster code */
        for (i = inlen; --i >= 0; ) {
            c = Py_CHARMASK(*input++);
            // 使用主体字符串中的字符的ASCII码作为索引值,
            // 从table字符串里得到对应的字符,并映射
            // 到output即结果字符串里。
            if (Py_CHARMASK((*output++ = table[c])) != c)
                changed = 1;
        }
        // 如果table字符串对应的ASCII码表被修改了,
        // 则将result结果字符串对象返回。
        if (changed || !PyString_CheckExact(input_obj))
            return result;
        // 如果table字符串对应的ASCII码表没被修改的话,
        // 也就是table里的每个字符的ASCII码都等于该字符在
        // table字符串中的索引值(或者叫偏移值)时,
        // 则直接将主体字符串对象返回,同时增加主体字符串对象的
        // 引用计数。
        Py_DECREF(result);
        Py_INCREF(input_obj);
        return input_obj;
    }

    // 当dellen不等于0,或者table为空指针时,
    // 则执行下面的代码。
    // 先将table字符串里的字符拷贝到trans_table中,
    // 如果table为空指针的话,则直接将0到256的ASCII码值
    // 拷贝到trans_table中。
    if (table == NULL) {
        for (i = 0; i < 256; i++)
            trans_table[i] = Py_CHARMASK(i);
    } else {
        for (i = 0; i < 256; i++)
            trans_table[i] = Py_CHARMASK(table[i]);
    }

    // 如果dellen不等于0(即有需要删除的字符时),则
    // 将trans_table中需要删除的字符设置为-1
    for (i = 0; i < dellen; i++)
        trans_table[(int) Py_CHARMASK(del_table[i])] = -1;

    for (i = inlen; --i >= 0; ) {
        c = Py_CHARMASK(*input++);
        // 如果trans_table[c]等于-1的话,
        // 说明该字符需要被删除掉,则不会将
        // trans_table[c]设置到output结果字符串里,
        // 如果trans_table[c]不为-1的话,
        // 则将trans_table[c]设置到output中
        if (trans_table[c] != -1)
            if (Py_CHARMASK(*output++ = (char)trans_table[c]) == c)
                continue;
        changed = 1;
    }
    // 如果trans_table对应的ASCII码表没发生修改的话,
    // 则直接将input_obj主体字符串对象返回。
    if (!changed && PyString_CheckExact(input_obj)) {
        Py_DECREF(result);
        Py_INCREF(input_obj);
        return input_obj;
    }
    // 通过_PyString_Resize来调整result结果字符串的尺寸,
    // 因为在上面可能删除了某些字符,从而让实际的尺寸小于分配的尺寸,
    // _PyString_Resize函数就可以针对这种情况来调整尺寸。
    /* Fix the size of the resulting string */
    if (inlen > 0 && _PyString_Resize(&result, output - output_start))
        return NULL;
    // 将result结果字符串对象返回
    return result;
}


    上面的translate__doc__变量对应的字符串信息为translate方法的帮助信息。此外,上面的string_translate为translate方法的底层C函数。从上面的代码和对应的注释(棕色的注释是此处额外添加的)里可以看到,该方法可以接受两个参数,第一个是必填的参数,表示需要映射的ASCII码字符串。第二个为可选参数,表示需要将主体字符串里的哪些字符给删除掉。

    translate方法的具体使用如下所示:

[email protected]:~$ python
Python 2.7.8 (default, Feb 20 2015, 12:54:46) 
[GCC 4.5.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import string
>>> table = string.maketrans('ABCD', '1234')
>>> 'AABBCCDD hello'.translate(table, 'hl')
'11223344 eo'
>>> 'AABBCCDD hello'.translate(None, 'hl')
'AABBCCDD eo'
>>> 'AABBCCDD hello'.translate(None)
'AABBCCDD hello'
>>> 'AABBCCDD hello'.translate('abcd')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: translation table must be 256 characters long
>>> quit()
[email protected]:~$ 


    从上面的输出中可以看到,当提供了第二个参数,比如上面的'hl'时,就将字符串里的hl字符给剔除掉了。此外,该方法的第一个参数可以设置为None,当该参数为None时,就表示采用标准的ASCII码表,这样,字符串中的字符就不会被映射为别的字符。最后,translate方法的第一个字符串参数必须包含256个字符,如果没有256个字符的话,就会抛出如上所示的ValueError异常。

max与min:

    max与min方法都属于内建模块里的函数,因此,它们对应的底层C函数是定义在Python/bltinmodule.c文件里的:

static PyObject *
min_max(PyObject *args, PyObject *kwds, int op)
{
    PyObject *v, *it, *item, *val, *maxitem, *maxval, *keyfunc=NULL;
    const char *name = op == Py_LT ? "min" : "max";

    // 可以给min与max方法提供多个参数,
    // 当提供了多个参数时,就在这些参数之间
    // 进行比较,并返回最大值或最小值,
    // 当op为Py_LT时,返回最小值,
    // 当op为Py_GT时,返回最大值,
    // 注意这些参数并不包括kwds词典在内
    // 例如: max('a', 'b', key=keyfunc)
    // 其中'a','b'会构成此处的args元组,
    // 而key=keyfunc则成为kwds词典里的成员,
    // 此时kwds词典里只有一个成员,该成员
    // 的key就是'key',对应的值为keyfunc
    // 又例如: max('a','b',key=keyfunc,max='hello')
    // 那么'a','b'依旧是构成args元组,
    // 但此时的kwds词典中就有了两个成员,
    // 一个是key->keyfunc即key为'key',值为keyfunc的成员,
    // 另一个则是max->'hello'即key为'max',值为'hello'的成员
    if (PyTuple_Size(args) > 1)
        v = args;
    // 当只提供了一个参数时,则只会对该参数的
    // 内部的元素进行比较,
    // 例如: max('abcd')执行时,就只会对'abcd'字符串内部
    // 的4个字符'a','b','c','d'进行比较。
    else if (!PyArg_UnpackTuple(args, (char *)name, 1, 1, &v))
        return NULL;

    // 将kwds词典中key为"key"的成员所对应的值提取出来,
    // 作为keyfunc,keyfunc的作用就是将需要比较的元素转换为
    // 实际进行比较的值。
    // 例如:
    // >>> def keyfunc(item):
    // ...   if(item == 'a'):
    // ...     return '2'
    // ...   elif(item == 'b'):
    // ...     return '1'
    // ... 
    // >>> max('ab', key = keyfunc)
    // 'a'
    // 上面例子中,'a'在keyfunc的作用下会转为'2',而
    // 'b'在keyfunc的作用下则会转为'1',因此,该例子中,
    // 'a'与'b'之间的比较就转为了'2'与'1'之间的比较,
    // 由于'2'的ASCII码大于'1',因此结果就显示'a'最大,
    // 但其实'a'的ASCII码是小于'b'的,只不过实际比较时,
    // 不是用的'a','b'的ASCII码来比较的,是用的
    // '2'和'1'来进行比较的。
    if (kwds != NULL && PyDict_Check(kwds) && PyDict_Size(kwds)) {
        keyfunc = PyDict_GetItemString(kwds, "key");
        if (PyDict_Size(kwds)!=1  ||  keyfunc == NULL) {
            PyErr_Format(PyExc_TypeError,
                "%s() got an unexpected keyword argument", name);
            return NULL;
        }
        Py_INCREF(keyfunc);
    }

    it = PyObject_GetIter(v);
    if (it == NULL) {
        Py_XDECREF(keyfunc);
        return NULL;
    }

    maxitem = NULL; /* the result */
    maxval = NULL;  /* the value associated with the result */
    while (( item = PyIter_Next(it) )) {
        // 如果提供了keyfunc,则从keyfunc中获取到
        // 实际需要进行比较的值来。
        /* get the value from the key function */
        if (keyfunc != NULL) {
            val = PyObject_CallFunctionObjArgs(keyfunc, item, NULL);
            if (val == NULL)
                goto Fail_it_item;
        }
        // 如果没提供keyfunc,则使用原始的值来进行比较。
        /* no key function; the value is the item */
        else {
            val = item;
            Py_INCREF(val);
        }

        /* maximum value and item are unset; set them */
        if (maxval == NULL) {
            maxitem = item;
            maxval = val;
        }
        /* maximum value and item are set; update them as necessary */
        else {
            // 根据op对val与maxval进行比较,
            // 如果是Py_LT操作(也就是获取最小值的操作)时,
            // 则当val小于maxval时,val就作为新的maxval,
            // 如果是Py_GT(也就是获取最大值的操作)时,
            // 则当val大于maxval时,val就作为新的maxval,
            // 对于字符串对象,PyObject_RichCompareBool最终会
            // 通过Objects/stringobject.c文件中的
            // string_richcompare函数来完成具体的比较操作。
            int cmp = PyObject_RichCompareBool(val, maxval, op);
            if (cmp < 0)
                goto Fail_it_item_and_val;
            else if (cmp > 0) {
                Py_DECREF(maxval);
                Py_DECREF(maxitem);
                maxval = val;
                maxitem = item;
            }
            else {
                Py_DECREF(item);
                Py_DECREF(val);
            }
        }
    }
    if (PyErr_Occurred())
        goto Fail_it;
    if (maxval == NULL) {
        PyErr_Format(PyExc_ValueError,
                     "%s() arg is an empty sequence", name);
        assert(maxitem == NULL);
    }
    else
        Py_DECREF(maxval);
    Py_DECREF(it);
    Py_XDECREF(keyfunc);
    // 将最大值或最小值返回
    return maxitem;

.....................................................
}

static PyObject *
builtin_min(PyObject *self, PyObject *args, PyObject *kwds)
{
    return min_max(args, kwds, Py_LT);
}

.....................................................

static PyObject *
builtin_max(PyObject *self, PyObject *args, PyObject *kwds)
{
    return min_max(args, kwds, Py_GT);
}


    上面的builtin_minbuiltin_max分别是min和max方法的底层C函数,它们最终都会通过min_max来获取到最小值或最大值。这两个方法的具体使用如下:

[email protected]:~$ python
Python 2.7.8 (default, Feb 20 2015, 12:54:46) 
[GCC 4.5.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> def keyfunc(item):
...   if(item == 'a'):
...     return '2'
...   elif(item == 'b'):
...     return '1'
... 
>>> max('ab', key = keyfunc)
'a'
>>> max('a', 'b')
'b'
>>> max('a', 'b', key=keyfunc)
'a'
>>> max('abc', 'ABC')
'abc'
>>> min('abc', 'ABC')
'ABC'
>>> max('abC', 'abc')
'abc'
>>> min('abC', 'abc')
'abC'
>>> max('hello', 'world', 'zengl.com')
'zengl.com'
>>> min('hello', 'world', 'zengl.com')
'hello'
>>> quit()
[email protected]:~$ 


S.replace:

    replace方法相关的底层C函数如下(这些函数都定义在Objects/stringobject.c文件中):

// 下面的replace_substring_in_place函数只会在
// from_s与to_s长度相同时,才使用的。
/* len(self)>=1, len(from)==len(to)>=2, maxcount>=1 */
Py_LOCAL(PyStringObject *)
replace_substring_in_place(PyStringObject *self,
                           const char *from_s, Py_ssize_t from_len,
                           const char *to_s, Py_ssize_t to_len,
                           Py_ssize_t maxcount)
{
    ................................................
    // 下面的self_s是主体字符串,
    // from_s是主体字符串里需要被替换掉的子字符串,
    // 先通过stringlib_find查找出from_s在self_s中的
    // offset偏移值,这样,后面就可以通过该偏移值,
    // 将to_s拷贝到offset位置处,
    // 从而完成用to_s替换from_s的操作。
    // 当然开头的替换操作只能对第一个from_s进行替换,
    // 最后还有一个while循环语句,会利用相同的原理,
    // 将self_s中剩余的from_s都替换为to_s,
    // 至于一共要替换多少次,则是由maxcount参数来决定的。
    offset = stringlib_find(self_s, self_len,
                            from_s, from_len,
                            0);

    ................................................

    // 返回的是一个新创建的字符串对象
    /* Need to make a new string */
    result = (PyStringObject *) PyString_FromStringAndSize(NULL, self_len);
    if (result == NULL)
        return NULL;
    result_s = PyString_AS_STRING(result);
    // 将主体字符串的原始数据全部拷贝到结果字符串中
    Py_MEMCPY(result_s, self_s, self_len);

    /* change everything in-place, starting with this one */
    start =  result_s + offset;
    // 根据offset偏移值(此处已转换为了start指针),
    // 将to_s拷贝到start位置处,覆盖掉原来的
    // from_s,由于to_s与from_s的长度相同,
    // 因此,覆盖替换操作,不会对结果字符串的长度产生影响。
    Py_MEMCPY(start, to_s, from_len);
    start += from_len;
    end = result_s + self_len;

    // 根据maxcount将余下的from_s都替换为to_s
    while ( --maxcount > 0) {
        offset = stringlib_find(start, end-start,
                                from_s, from_len,
                                0);
        if (offset==-1)
            break;
        Py_MEMCPY(start+offset, to_s, from_len);
        start += offset+from_len;
    }

    return result;
}

....................................................

// 当from_s与to_s长度不同时,则会使用下面的函数来完成替换工作
/* len(self)>=1, len(from)>=2, len(to)>=2, maxcount>=1 */
Py_LOCAL(PyStringObject *)
replace_substring(PyStringObject *self,
                  const char *from_s, Py_ssize_t from_len,
                  const char *to_s, Py_ssize_t to_len,
                  Py_ssize_t maxcount) {
    ................................................
    // 在from_s与to_s长度不同的情况下,
    // 就需要将主体字符串分段拷贝到结果字符串中
    // 例如: 'hello hello'.replace('ll', 'mnz')在执行时,
    // 会先创建一个结果字符串对象,
    // 然后先将主体字符串里的'he'拷贝到结果字符串,此时的
    // 结果字符串变为'he',再将'mnz'拷贝到结果字符串,此时的
    // 结果字符串变为'hemnz',再接着将'o he'拷贝到结果字符串,
    // 此时的结果字符串就变为'hemnzo he',接着再将'mnz'
    // 拷贝到结果字符串,结果字符串就变为'hemnzo hemnz',
    // 最后将剩下的'o'拷贝到结果字符串,结果字符串最终就变为
    // 'hemnzo hemnzo',这样,'ll'就替换为'mnz'了。
    while (count-- > 0) {
        // 从start位置处开始,查找出from_s在主体字符串
        // 里的相对于start的offset偏移值
        offset = stringlib_find(start, end-start,
                                from_s, from_len,
                                0);
        // 如果找不到则直接跳出循环
        if (offset == -1)
            break;
        next = start+offset;
        if (next == start) {
            // 如果from_s位于主体字符串的起始位置的话,
            // 则直接将to_s拷贝到result_s结果字符串
            // 的起始位置处。
            /* replace with the 'to' */
            Py_MEMCPY(result_s, to_s, to_len);
            // 重新设置result_s与start指针,为下一次的
            // 查找与拷贝操作,做准备。
            result_s += to_len;
            start += from_len;
        } else {
            // 如果from_s位于主体字符串的中间位置,
            // 则先将from_s之前的主体字符串里的数据
            // 拷贝到结果字符串中
            /* copy the unchanged old then the 'to' */
            Py_MEMCPY(result_s, start, next-start);
            result_s += (next-start);
            // 再将to_s拷贝到结果字符串
            Py_MEMCPY(result_s, to_s, to_len);
            // 重新设置result_s与start指针,为下一次的
            // 查找与拷贝操作,做准备。
            result_s += to_len;
            start = next+from_len;
        }
    }
    // 将主体字符串中,余下的数据拷贝到结果字符串。
    /* Copy the remainder of the remaining string */
    Py_MEMCPY(result_s, start, end-start);

    return result;
}

Py_LOCAL(PyStringObject *)
replace(PyStringObject *self,
    const char *from_s, Py_ssize_t from_len,
    const char *to_s, Py_ssize_t to_len,
    Py_ssize_t maxcount)
{
    if (maxcount < 0) {
        maxcount = PY_SSIZE_T_MAX;
    } else if (maxcount == 0 || PyString_GET_SIZE(self) == 0) {
        /* nothing to do; return the original string */
        return return_self(self);
    }

    ................................................

    if (from_len == to_len) {
        if (from_len == 1) {
            return replace_single_character_in_place(
                self,
                from_s[0],
                to_s[0],
                maxcount);
        } else {
            return replace_substring_in_place(
                self, from_s, from_len, to_s, to_len, maxcount);
        }
    }

    /* Otherwise use the more generic algorithms */
    if (from_len == 1) {
        return replace_single_character(self, from_s[0],
                                        to_s, to_len, maxcount);
    } else {
        /* len('from')>=2, len('to')>=1 */
        return replace_substring(self, from_s, from_len, to_s, to_len, maxcount);
    }
}

static PyObject *
string_replace(PyStringObject *self, PyObject *args)
{
    // count的缺省值为-1,该值(小于0时)会在上面的replace函数中被转换为PY_SSIZE_T_MAX,
    // PY_SSIZE_T_MAX是一个很大的数,就表示将主体字符串里的所有需要替换的字符串都替换掉。
    Py_ssize_t count = -1;
    ................................................
    // replace方法的第一个from与第二个to参数是必须提供的参数,
    // 表示需要将主体字符串里的from字符串替换为to字符串,
    // 第三个count参数表示最多替换多少次。缺省值为-1,表示将所有的from都替换为to。
    if (!PyArg_ParseTuple(args, "OO|n:replace", &from, &to, &count))
        return NULL;

    ................................................

    // 最后通过上面的replace函数来完成具体的替换操作。
    return (PyObject *)replace((PyStringObject *) self,
                               from_s, from_len,
                               to_s, to_len, count);
}


    replace方法对应的底层C函数为上面所示的string_replace函数,该函数最终会进入到replace这个C函数中。在replace函数里,会根据情况选择使用replace_single_character_in_place,replace_substring_in_place
replace_single_character或者replace_substring函数来完成具体的替换操作,其中,replace_substring_in_placereplace_substring已经给出了代码和相关的注释,另外两个replace_single_character_in_place与replace_single_character函数则是用于对单个字符进行替换的情况,限于篇幅这里没给出它们的代码(它们与上面显示出来的两个函数的代码,在逻辑结构上并没有什么太多的差别)。

    replace方法的具体使用,如下所示:

[email protected]:~$ python
Python 2.7.8 (default, Feb 20 2015, 12:54:46) 
[GCC 4.5.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> 'hello'.replace('ll', 'mn')
'hemno'
>>> 'hello hello'.replace('ll', 'mnz')
'hemnzo hemnzo'
>>> 'hello hello hello'.replace('ll', 'mn', 2)
'hemno hemno hello'
>>> 'hello hello hello'.replace('ll', 'mn', 1)
'hemno hello hello'
>>> 'hello hello'.replace('ll', 'mnz', 1)
'hemnzo hello'
>>> 'hello hello'.replace('ll', 'mnz', 0)
'hello hello'
>>> 'hello hello'.replace('ll', 'mnz', -1)
'hemnzo hemnzo'
>>> 'hello hello'.replace('ll', 'mnz', -2)
'hemnzo hemnzo'
>>> quit()
[email protected]:~$ 


    可以看到第三个可选参数,表示需要替换的次数。当该参数为0时,则什么也不做,直接返回原始的字符串。当该参数为负数时,就和缺省情况一样,表示将所有需要替换的字符串都替换掉。

S.split与S.splitlines:

    split与splitlines方法,对应的底层C函数如下(都定义在Objects/stringobject.c文件里):

PyDoc_STRVAR(split__doc__,
"S.split([sep [,maxsplit]]) -> list of strings\n\
\n\
Return a list of the words in the string S, using sep as the\n\
delimiter string.  If maxsplit is given, at most maxsplit\n\
splits are done. If sep is not specified or is None, any\n\
whitespace string is a separator and empty strings are removed\n\
from the result.");

static PyObject *
string_split(PyStringObject *self, PyObject *args)
{
    Py_ssize_t len = PyString_GET_SIZE(self), n;
    Py_ssize_t maxsplit = -1;
    const char *s = PyString_AS_STRING(self), *sub;
    PyObject *subobj = Py_None;

    // 从脚本中获取到split方法的两个参数,
    // 将第一个参数设置到subobj变量,
    // 并将第二个参数设置到maxsplit变量,
    // 这两个参数都是可选参数,subobj的缺省值是None,
    // maxsplit的缺省值是-1,这两个缺省值是在函数的开头
    // 就已经被设置好了的。
    // split方法会使用subobj作为分割字符串,
    // 将self主体字符串分割为多个字符串所构成的列表,
    // 例如: 'aa--bb--cc--dd'.split('--')脚本执行后,
    // 得到的结果就会是: ['aa', 'bb', 'cc', 'dd'] 。
    // maxsplit表示最多分割多少次,
    // 例如: 'aa--bb--cc--dd'.split('--', 2)得到的结果
    // 就是: ['aa', 'bb', 'cc--dd'],也就是最多只分割两次。
    if (!PyArg_ParseTuple(args, "|On:split", &subobj, &maxsplit))
        return NULL;
    // 当maxsplit的值小于0时,
    // 就将其设置为PY_SSIZE_T_MAX,
    // PY_SSIZE_T_MAX是一个很大的数,
    // 因此,缺省情况下,就是将所有能分割
    // 的字符串都进行分割。
    if (maxsplit < 0)
        maxsplit = PY_SSIZE_T_MAX;
    // 当subobj为None时,就通过
    // stringlib_split_whitespace函数
    // 使用空白字符来进行分割。
    // 例如: 'aa \n\rbb\f\fcc\v\v\rdd'.split()得到的
    // 结果就是: ['aa', 'bb', 'cc', 'dd']
    // stringlib_split_whitespace函数定义在
    // Objects/stringlib/split.h的文件中
    if (subobj == Py_None)
        return stringlib_split_whitespace((PyObject*) self, s, len, maxsplit);
    // 如果subobj不为None,且subobj是一个
    // 有效的字符串对象,则使用subobj来作为分割字符串。
    // 下面的sub是subobj对象的字符串指针,
    // 下面的n则是subobj对象的字符串数据
    // 所包含的字符个数。
    if (PyString_Check(subobj)) {
        sub = PyString_AS_STRING(subobj);
        n = PyString_GET_SIZE(subobj);
    }
    ................................................

    // 使用stringlib_split函数,根据sub字符串,
    // 将self主体字符串最多分割maxsplit次,分割后,
    // 得到的列表作为结果返回。
    // stringlib_split函数定义在
    // Objects/stringlib/split.h的文件中。
    return stringlib_split((PyObject*) self, s, len, sub, n, maxsplit);
}

....................................................

PyDoc_STRVAR(splitlines__doc__,
"S.splitlines(keepends=False) -> list of strings\n\
\n\
Return a list of the lines in S, breaking at line boundaries.\n\
Line breaks are not included in the resulting list unless keepends\n\
is given and true.");

static PyObject*
string_splitlines(PyStringObject *self, PyObject *args)
{
    int keepends = 0;

    // splitlines方法用于将self里的多行字符串,
    // 根据换行符来进行分割,分割所形成的列表作为结果返回。
    // keepends参数为可选参数,缺省值为0,
    // 当脚本提供的参数为布尔对象时,
    // True在此处会被转为1,False则被转为0,
    // 当keepends为0时,不会保留换行符。
    // 当keepends不为0时,则会将换行符保留下来。
    // 例如: 'hello\r\nhello'.splitlines(False)执行后,
    // 得到的结果就是: ['hello', 'hello'] ,
    // 又例如: 'hello\r\nhello'.splitlines(True)执行后,
    // 得到的结果就会是: ['hello\r\n', 'hello']
    if (!PyArg_ParseTuple(args, "|i:splitlines", &keepends))
        return NULL;

    // 最后通过stringlib_splitlines函数
    // 来完成具体的分割操作,
    // 该函数定义在Objects/stringlib/split.h文件中。
    return stringlib_splitlines(
        (PyObject*) self, PyString_AS_STRING(self), PyString_GET_SIZE(self),
        keepends
    );
}


    上面的split__doc__是split方法的帮助文档,string_split函数是split方法在执行时会调用的底层C函数。另外,splitlines__doc__是splitlines方法的帮助文档,string_splitlines函数则是splitlines方法的底层C函数。这两个方法的具体使用,如下所示:

[email protected]:~$ python
Python 2.7.8 (default, Feb 20 2015, 12:54:46) 
[GCC 4.5.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> 'aa--bb--cc--dd'.split('--')
['aa', 'bb', 'cc', 'dd']
>>> 'aa--bb--cc--dd'.split('--', 2)
['aa', 'bb', 'cc--dd']
>>> 'aa--bb--cc--dd'.split('--', 1)
['aa', 'bb--cc--dd']
>>> 'aa\r\nbb\v\vcc\f\f\t\tdd'.split(None, 2)
['aa', 'bb', 'cc\x0c\x0c\t\tdd']
>>> 'aa\r\nbb\v\vcc\f\f\t\tdd'.split(None)
['aa', 'bb', 'cc', 'dd']
>>> 'aa\r\nbb\v\vcc\f\f\t\tdd'.split()
['aa', 'bb', 'cc', 'dd']
>>> 'aa\r\nbb\v\vcc\f\f\t\tdd'.split(None, -3)
['aa', 'bb', 'cc', 'dd']
>>> 'aa\r\nbb\v\vcc\f\f\t\tdd'.split(None, 0)
['aa\r\nbb\x0b\x0bcc\x0c\x0c\t\tdd']
>>> 'hello\r\nhello'.splitlines(True)
['hello\r\n', 'hello']
>>> 'hello\r\nhello'.splitlines(False)
['hello', 'hello']
>>> 'hello\r\nhello'.splitlines()
['hello', 'hello']
>>> 'hello\r\nhello'.splitlines(-2)
['hello\r\n', 'hello']
>>> 'hello\r\nhello'.splitlines(-3)
['hello\r\n', 'hello']
>>> 'hello\r\nhello'.splitlines(0)
['hello', 'hello']
>>> 'hello\r\nhello'.splitlines(1)
['hello\r\n', 'hello']
>>> 'hello\r\nhello'.splitlines(2)
['hello\r\n', 'hello']
>>> 'hello\r\nhell\nhello'.splitlines()
['hello', 'hell', 'hello']
>>> 'hello\r\nhell\nhello'.splitlines(True)
['hello\r\n', 'hell\n', 'hello']
>>> 'hello\r\nhell\nhello'.splitlines(3)
['hello\r\n', 'hell\n', 'hello']
>>> quit()
[email protected]:~$ 


S.swapcase:

    swapcase方法对应的底层C函数如下(定义在Objects/stringobject.c文件中):

PyDoc_STRVAR(swapcase__doc__,
"S.swapcase() -> string\n\
\n\
Return a copy of the string S with uppercase characters\n\
converted to lowercase and vice versa.");

static PyObject *
string_swapcase(PyStringObject *self)
{
    char *s = PyString_AS_STRING(self), *s_new;
    Py_ssize_t i, n = PyString_GET_SIZE(self);
    PyObject *newobj;

    // 根据self主体字符串的长度,
    // 创建一个新的copy字符串对象
    newobj = PyString_FromStringAndSize(NULL, n);
    if (newobj == NULL)
        return NULL;
    // 得到copy字符串对象的数据指针
    s_new = PyString_AsString(newobj);
    for (i = 0; i < n; i++) {
        int c = Py_CHARMASK(*s++);
        // 当主体字符串里的字符为小写字母时,
        // 就将其转为大写字母,
        // 并存储到结果字符串中。
        if (islower(c)) {
            *s_new = toupper(c);
        }
        // 如果是大写字母,就转为小写字母。
        else if (isupper(c)) {
            *s_new = tolower(c);
        }
        // 其他的字符则保持不变
        else
            *s_new = c;
        s_new++;
    }
    // 将copy字符串对象作为结果返回
    return newobj;
}


    从上面的代码中,可以看到,swapcase方法其实就是将字符串里的原大写字母转为小写字母,原小写字母转为对应的大写字母,其它的非大小写敏感的字符则保持不变。该方法的具体使用如下:

[email protected]:~$ python
Python 2.7.8 (default, Feb 20 2015, 12:54:46) 
[GCC 4.5.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> 'Hello World ZenGl!!'.swapcase()
'hELLO wORLD zENgL!!'
>>> quit()
[email protected]:~$ 


S.title:

    title方法对应的底层C函数如下(也定义在Objects/stringobject.c文件中):

PyDoc_STRVAR(title__doc__,
"S.title() -> string\n\
\n\
Return a titlecased version of S, i.e. words start with uppercase\n\
characters, all remaining cased characters have lowercase.");

// 为主体字符串创建一个标题样式的copy字符串,
// 在标题样式中,所有单词的首字母都是大写字母,
// 单词的其余字母则都是小写字母。
// 字符串中的非大小写敏感的字符,
// 则起到分隔单词的作用,
// 最后将该标题样式的copy字符串作为结果返回
static PyObject*
string_title(PyStringObject *self)
{
    char *s = PyString_AS_STRING(self), *s_new;
    Py_ssize_t i, n = PyString_GET_SIZE(self);
    int previous_is_cased = 0;
    PyObject *newobj;

    // 根据self主体字符串的数据长度,
    // 创建一个新的copy字符串对象
    newobj = PyString_FromStringAndSize(NULL, n);
    if (newobj == NULL)
        return NULL;
    // 获取copy字符串对象的数据指针
    s_new = PyString_AsString(newobj);
    for (i = 0; i < n; i++) {
        int c = Py_CHARMASK(*s++);
        // 将单词的首字母都设置为大写字母
        if (islower(c)) {
            if (!previous_is_cased)
                c = toupper(c);
            previous_is_cased = 1;
        // 将单词的其余字母都设置为小写字母
        } else if (isupper(c)) {
            if (previous_is_cased)
                c = tolower(c);
            previous_is_cased = 1;
        // 其他的非大小写敏感的字符,
        // 则起到分隔单词的作用
        } else
            previous_is_cased = 0;
        *s_new++ = c;
    }
    // 将标题样式的copy字符串对象作为结果返回
    return newobj;
}


    上面的title__doc__是title方法的帮助文档,string_title则是title方法的底层C函数。title方法就是用于生成标题样式的字符串的,具体使用如下:

[email protected]:~$ python
Python 2.7.8 (default, Feb 20 2015, 12:54:46) 
[GCC 4.5.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> 'hello world android'.title()
'Hello World Android'
>>> 'hel123lo wor~~ld zengl.com'.title()
'Hel123Lo Wor~~Ld Zengl.Com'
>>> quit()
[email protected]:~$ 


    可以看到,标题样式的字符串里的数字,小数点之类的非大小写敏感的字符,会将左右两侧的字母分隔为两个单词。每个单词的首字母都是大写字母,单词的其余部分则都是小写字母。

S.zfill:

    zfill方法对应的底层C函数如下(也定义在Objects/stringobject.c文件中):

PyDoc_STRVAR(zfill__doc__,
"S.zfill(width) -> string\n"
"\n"
"Pad a numeric string S with zeros on the left, to fill a field\n"
"of the specified width.  The string S is never truncated.");

// 根据width宽度参数,在字符串的左侧填充'0'字符
static PyObject *
string_zfill(PyStringObject *self, PyObject *args)
{
    Py_ssize_t fill;
    PyObject *s;
    char *p;
    Py_ssize_t width;

    // 从脚本中获取width宽度信息,该参数是必填参数
    if (!PyArg_ParseTuple(args, "n:zfill", &width))
        return NULL;

    // 当width参数小于等于self主体字符串的字符个数时,
    // 直接将self字符串对象返回
    if (PyString_GET_SIZE(self) >= width) {
        if (PyString_CheckExact(self)) {
            Py_INCREF(self);
            return (PyObject*) self;
        }
        else
            return PyString_FromStringAndSize(
            PyString_AS_STRING(self),
            PyString_GET_SIZE(self)
            );
    }

    // 通过width - PyString_GET_SIZE(self)
    // 计算出fill值,也就是需要在字符串的左侧
    // 填充多少个'0'
    fill = width - PyString_GET_SIZE(self);

    // 通过pad函数,创建一个self的copy拷贝字符串对象,
    // 并在copy字符串的左侧,填充fill个'0'字符
    s = pad(self, fill, 0, '0');

    if (s == NULL)
        return NULL;

    p = PyString_AS_STRING(s);
    // 将原字符串里的正负号放置到'0'字符的前面
    // 不过只能将第一个'+'或'-'放置到最前方,
    // 例如: '++12345'.zfill(12)执行后,得到的结果
    // 就会是: '+00000+12345' ,因为下面的代码
    // 只对开头的'+'或'-'字符做了判断
    if (p[fill] == '+' || p[fill] == '-') {
        /* move sign to beginning of string */
        p[0] = p[fill];
        p[fill] = '0';
    }

    // 将copy字符串对象返回
    return (PyObject*) s;
}


    上面的zfill__doc__是zfill方法的帮助文档,而string_zfill则是zfill方法的底层C函数。在string_zfill函数中所使用的pad函数,在之前介绍S.center方法时,已经介绍过了。

    zfill方法的具体使用如下:

[email protected]:~$ python
Python 2.7.8 (default, Feb 20 2015, 12:54:46) 
[GCC 4.5.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> '++12345'.zfill(12)
'+00000+12345'
>>> 'hello'.zfill(9)
'0000hello'
>>> '-0.1234'.zfill(11)
'-00000.1234'
>>> '123456'.zfill(3)
'123456'
>>> quit()
[email protected]:~$ 


本章结束语:

    以上就是Python中字符串相关的函数,其余没介绍到的字符串函数,请自行查看相关的C源代码。

    下一章将介绍List列表相关的内容。

    人生就像打橄榄球一样,不能犯规,也不要闪避球,而应向底线冲过去。

——  罗斯福
 
上下篇

下一篇: Python列表类型

上一篇: Python字符串类型

相关文章

Python随机数函数

Python列表类型

Python元组类型及相关函数

Python相关的数学运算函数

Python的calendar模块

Python的流程控制语句