无名氏说:编程有两件事,一件是处理数值;另一件是处理字符串。
要我说,对于商业应用编程来说,处理字符串的代码可能超过八成,所以掌握字符串的基本用法尤其重要。 通过Python教程,已经掌握了基本的字符串字面量语法,比如 u 、 r 前缀等, 但对于怎么更好地编写多行的字符串字面量,仍然有个小技巧向大家推介。
s=("select * "
"from atable "
"where afield='value'")
s
"select * from atable where afield='value'"
这就是利用Python遇到未闭合的小括号时会自动将多行代码拼接为一行和把相邻的两个字符串字面摄拼接在一起的特性做到的。 相比使用3个连续的单(双)引号,这种方式不会把换行符和前导空格也当作字符串的一部分, 则更加符合用户的思维习惯。
除了这个小技巧,Python中的字符串其实有 str 和 unicode 两种。虽然在Python 3中已经简化为一种。
a="hi"
isinstance(a,str)
True
b=u"Hi"
isinstance(b,str)
True
但如果你还在编写运行在Python 2上的 程序,当需要判断变量是否为字符串时,需要注意了:
判断一个变量 s 是不是字符串应使用 isinstance(s,basestring) , 注意这里的参数是 basestring 而不是 str 。
同样的问题,包括 isinstance(b,unicode) ,这个在 Python3内无法执行,Python2内可以运行。
isinstance(a,str) 用于判断一个字符串是不是普通字符串,也就是说其类型是否为 str ; 因此当被判断的字符串为 Unicode 的时候,返回 False 。 同样, isinstance(a,unicode) 用来判断一个字符串是不是Unicode。 因此要正确判断一个变 量是不是字符串,应该使用 isinstance(s,basestring) , 因为 basestring 才是是 str 和 Unicode 的基类,包含了普通字符串和 Unicode 类型。
接下来正式开始学习字符串的基本用法。与其他书籍、手册不同, 我们将通过性质判定、査找替换、分切与连接、变形、填空与刪减等5个方面来学习。
类型判定
首先是性质判定, str 对 象有以下几个方法: isa]num() , isinpha() 、 isdigit() 、 islower()、 isuppier() 、 isspace() 、 istitle() 、 startswith(prefix, start[, end]]) 、 endswith(suffix[,start[,end]) 。 前面几个 is*() 形式的函数很简单,就是判定是否数字、字母、大小写、空白符之类的, istitle() 作为东方人用得少些,它是判定字符串是否每个单词都有且只有第一个字母是大写的。
'5'.isnumeric()
True
'5'.isdigit()
True
'5'.isalpha()
False
'b'.isalpha()
True
assert "Hello World".istitle()==True
assert "Hello world".istitle()==False
相对于 is*() 这些“小儿科"来说,需要注意的是*with()函数族可以接受可选的start、 end参数, 善加利用,可以优化性能。 另外,自Python 2-5版本起,*with()函数族的prefix 参数可以接受tuple类型的实参,当实参中的某个元素能够匹配时,即返回True。
查找与替换
接下来是査找与替换,count(sub[, start[,end]])、find( sub[, start[,end]])、 index( sub[, start[,end]])、rfind( sub[, start[,end]])、rindex( sub[,start[, end]])这些方法都接受 start、 end参数,善加利用,可以优化性能。其中count()能够査找子串sub在字符串中出现的次数, 这个数值在调用replace方法的时候用得着。此外,需要注意find()和index()方法的不同: find()函数族找不到时返回-1, index()函数族则抛出ValueError异常。 但对于判定是否包含子串的判定并不推荐调用这些方法,而是推荐使用in和not in操作符。
str="Test if a string contains some spacial substrings"
if str.find("some")!=-1:
print("yes it contains")
yes it contains
if "some" in str:
print("yes it contains using in ")
yes it contains using in
replace(old, new[,count])用以替换字符串的某些子串,如果指定count参数的话, 就最多替换count次,如果不指定,就全部替换(跟其他语言不太一样,需要注意)。
切分与连接
然后要掌握字符串的分切与连接,在这里,专讲分切。 partition(sep)、 rpartition(sep)、 splitlines([keepends])、 split([sep [,maxsplit]])、 rsplit([sep[,maxsplit]), 别看这些方法好像很多,其实只要弄清楚partition()和spht()就可以了。*partition()涵数族是 2.5版本新增的方法, 它接受一个字符串参数,并返冋一个3个元素的元组对象。如果sep没出现在母串中,返回值是(set,","); 否则,返回值的第一个元素是sep左端的部分,第二个元素是sep自身,第三个元素是sep右端的部分。 而split()的参数maxsplit是分切的次数,即最大的分切次数,所以返回值最多有maxsplit+1个元索。 但split()有不少小陷阱需要注意, 比如对于字符串s、s.split()和s.split("")的返回值是不相同的。
"hello world".split()
['hello', 'world']
"hello world".split(" ")
['hello', '', '', '', 'world']
产生差异的原因在于:当忽略 sep 参数或 sep 参数为 None 时与明确给 sep 賦予字符串值时, split() 采用两种不同的算法。对于前者,split() 先去除字符申两端的空白符, 然后以任意 长度的空内符串作为界定符分切字符串(即连续的空白符串被当作单一的空内符看待); 对于后者则认为两个连续的 sep 之间存在一个空字符串。因此对于空字符串(或空白符串), 它们 的返回值也是不同的。
"".split()
[]
"".split(" ")
['']
"hello wOrld".capitalize()
'Hello world'
"hello wOrld".swapcase()
'HELLO WoRLD'
"hello wOrld".title()
'Hello World'
因为函数并不去除字符串两端的空白符也不会把连续的空白符替换为一个空格, 所以不能把 title() 理解先以空白符分切字符串, 然后调用 capitalize() 处理每个字词以使其 首宇母大写,再用空格将它们连接在一起。 如果你有这样的需求,建议使用 string 模块中的 capwords(s) 函数, 它能够去除两端的空白符,再将连续的空白符用一个空格代替。
" hello world".title()
' Hello World'
import string
string.capwords(" hello world")
'Hello World'
看,它们的结果是不相同的。
字符串格式化:删减与填充
最后是删减与填充。
删减在文本处理是很常用,我们 常常得把字符串描头去尾,就用得上它们。
如果 strip([chars]) 、 lstrip([chars]) 、 mrip(fchars]) 中的 chars 参数没有指定, 就是删除空白符,空白符由 string.whitespace 常量定义。
填充则 常用于字符串的输出,借助它们能够排出漂亮的版面。 center(width[, fillchar]) 、 ljust(width [,:fillchar]) , ijust(width[,fillchar]) 、 zfill(width) 、 expandtabs([tabsize]) ,看,有了它们,居中、 左对齐、右对齐什么的完全不在话下。 这些方法中的 fillchar 参数是指用以填充的字符,默认 是空格。 而 zfill() 中的 z 是指 zero ,所以顾名思义,即是以 字符 0 进行填充, 在输出数值时比较常用。 expandtabs() 的 tabsize 参数默认为 8 ,它的功能是把字符串中的制表符(tab) 转换为适当数字的空格。