一、字符串操作
常用的 Python 字符串操作包括索引、分片、替换、删除、截取、复制、连接、比较、查找、分割等。另外 Python 2 字符串不支持国际编码,其大小为 8 bit,要想支持国际编码,需使用方法 u”content”。而在 Python 3 中默认已经支持国际编码了,不在需要使用 u 可以自动识别,其大小为 16 bit。
- 索引运算:key[index]
Python 索引是从 0 开始的,当索引超出了范围时,Python 会报一个 IndexError 错误。所以,要确保索引不要越界,记得最后一个元素的索引是 len(classmates) – 1,如果要取最后一个元素,除了计算索引位置外,还可以用 -1 做索引,直接获取最后一个元素。切片操作对列表来说是使用非常广泛的,灵活性特别大。
1 2 3 |
>>> string = "www.ywnds.com" >>> print(string[0]) w |
- 切片运算:key[index_start:index_end]
切片之后创建的是一个新的内存对象。
1 2 3 4 5 6 7 8 9 10 |
>>> print(string[1]) w >>> print(string[1:]) ww.ywnds.com >>> print(string[0:3]) www >>> print(string[-3:]) com >>> print(string[:-4]) www.ywnds |
- 扩展切片运算:key[index_start:index_end:stride]
1 2 3 4 5 6 7 8 9 |
# 字符 >>> print(string[4:13]) ywnds.com >>> print(string[4:13:2]) ynscm >>> print(string[-1::-1]) moc.sdnwy.www |
- 字符串拼接
用 + 号表示两个字符串的连接。
1 2 3 4 5 6 7 8 |
>>> str1 = "hello" >>> str2 = "world" >>> print(str1 + str2) helloworld >>> print(str1 + ' ' + str2) hello world |
- 字符串复制
用 * 号表示字符串复制,表达的意思其实跟数学上是一样的,多个相加嘛。
1 2 3 4 5 6 7 8 |
>>> print(str1*2) hellohello >>> print('#'*20) #################### >>> print(' '*20 + 'end') end |
- 字符串格式化
1 2 3 4 5 |
>>> print("%s" % "hello") hello >>> '{name},{alias}'.format(name='dkey',alias='ywnds') 'dkey,ywnds' |
- 相关函数
1 2 3 4 5 6 7 8 9 10 |
# 取一个字符串的长度 >>> len('string') 6 # 字符串最大最小值 >>> max('string') 't' >>> min('string') 'g' |
其实就所对应的 Ascii 编码最大最小的字符。
二、字符串内置方法
- str.upper()
将一个字符串转变为大写。
1 2 3 |
>>> string = 'hello' >>> string.upper() 'HELLO' |
- str.lower()
将一个字符串转变为小写。
1 2 3 |
>>> string = 'Hello' >>> string.lower() 'hello' |
- str.capitalize()
将一个字符串首字母转换我大写。
1 2 3 |
>>> string = 'hello' >>> string.capitalize() 'Hello' |
- str.strip([chars])
返回去除两侧(不包括内部)指定字符串,默认是去除空格;另外还有 rstrip 和 lstrip,分别是删除右边和左边指定字符。
1 2 3 4 5 6 7 |
>>> string = ' hello ' >>> string.strip() 'he llo' >>> string = 'hello' >>> string.strip('o') 'hell' |
- str.index(sub[, start[, end]])
找到指定字符串首次出现的位置,[, start[, end]] 表示从哪里开始和结束,可省略。
1 2 3 |
>>> string = 'hello' >>> string.index('l') 2 |
- str.replace(old, new[, count])
替换一个字符或一个字符串,其中 old 表示修改前内容,new 表示修改后内容,count 表示要修改几个,可省略。
1 2 3 4 5 6 7 8 |
# 替换字符 >>> string = 'hello' >>> string.replace('l','L',2) 'heLLo' # 删除字符 >>> string.replace('e','') 'hllo' |
- str.split(sep=None, maxsplit=-1)
用来将字符串分割成序列,可以执行最大分割多少次。
1 2 3 4 |
>>> string = "www.ywnds.com" >>> string.split('.') ['www', 'ywnds', 'com'] |
配置索引运算,可以显示执行的元素:
1 2 |
>>> string.split('.')[0] 'www' |
- str.startswith(suffix[, start[, end]])
判断对象中是否为执行字符首部,是则为真,否则为假。
1 2 3 4 5 6 |
>>> string = 'hello' >>> string.startswith('h') True >>> string.startswith('o') False |
- str.endswith(suffix[, start[, end]])
判断对象中是否为执行字符结尾,是则为真,否则为假。
1 2 3 4 5 6 |
>>> string = 'hello' >>> string.endswith('l') False >>> string.endswith('o') True |
- str.join(iterable)
使用’某某’作为分隔符连接序列中的字符。
1 2 3 4 5 6 |
>>> list = ['w','w','w','.','y','w','n','d','s','.','o','r','g'] >>> ''.join(list) 'www.ywnds.org' >>> '.'.join(list) 'w.w.w...y.w.n.d.s...o.r.g' |
- str.find(sub[, start[, end]])
可以在一个较长的字符串中查找子串,它返回子串所在位置的最左端索引,如果没有找到则返回 -1。
1 2 3 4 5 6 7 8 9 |
>>> string = "www.ywnds.com" >>> string.find('s') 8 >>> string.find('ywnds') 4 >>> string.find('ywd') -1 |
- str.translate(table)
这个方法和 replace 方法一样,可以替换字符串中的某些部分,但是和前者不同的是,translate 方法只处理单个字符。它的优势在于可以同时进行多个替换,有些时候比 replace 效率高的多。
- str.format()
格式化输出字符串。简单的说就是 format 里面的东西去替换前面的内容,在替换的时候,可以按某种规定来输出;format 方法在 Python 2.6 之后引入,替代了原先的 %,显得更加优雅。Python 3.6 又引入了字符串格式化更加快和优化的 F 操作符,具体可以看相关文章。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
>>> name = 'dkey' >>> name.format() 'dkey' # 通过位置 >>> '{0},{1}'.format('dkey',20) 'dkey,20' >>> '{},{}'.format('dkey',20) 'dkey,20' >>> '{0},{1},{0}'.format('dkey',20) 'dkey,20,dkey' # 通过关键字; >>> '{name},{age}'.format(age=18,name='dkey') 'dkey,18' # 通过映射LIST; >>> list = ['dkey',20,'china'] >>> print('my name is {0[0]},from {0[2]},age is {0[1]}'.format(list)) my name is dkey,from china,age is 20 # 用来做金额的千位分隔符; >>> '{:,}'.format(1234567890) '1,234,567,890' |
- str.isalnum()
是否全为字母或数字。
- str.isalpha()
是否为全字母。
- str.isdigit()
是否为全数字。
- str.islower()
是否为全小写。
- str.isupper()
是否为全大写。
- str.isspace()
是否为空格。
- str.isdecimal()
是否为小数。
还有很多方法,如: center()、decode()、encode()、rindex()、rsplit() 等。
三、join 方法使用
下面再来看看 join 方法的一些高级用法,非常实用。比如把一个列表处理成字符串。
1 2 3 |
>>> list = ['w','w','w','.','y','w','n','d','s','.','o','r','g'] >>> ''.join(list) 'www.ywnds.org' |
join 可以连接一个可迭代对象,当列表中都是字符时可以直接处理。但是如果一个可迭代对象中有不是字符类型的对象时,就无法像上面那样直接处理了。所以我们可以在 join 内使用循环语句把对象全部通过str()函数处理成字符串。
1 2 3 |
>>> list = ['a','b',123] >>> ','.join(str(v) for v in list) 'a,b,123' |
如果我在把列表处理成字符串时需要把每个对象都加上引号,早join中可以这么处理,如下代码:
1 2 |
>>> ','.join('\'' + str(v) + '\'' for v in list) "'a','b','123'" |
是不是很完美。
在复杂一点,如果需要对应列表中的对象,列表中是什么类型,在处理成字符串时还变成什么类型。如下:
1 2 3 4 5 6 7 |
# Python 2.7 >>> ','.join('\'' + str(v) + '\'' if isinstance(v, str) or isinstance(v, unicode) else str(v) for v in list) "'a','b',123" # Python 3.5 >>> ','.join('\'' + str(v) + '\'' if isinstance(v, str) else str(v) for v in list) "'a','b',123" |
就是在 join 中先循环,再判断。
基本意思就是,循环 list,得出变量v。如果 v 是 str 或者 unicode 就加上分号,如果不是这两种类型就直接显示即可。
如果不知道这么做有什么用的话?可以把 MySQL 查询结果输出为 INSERT 语句,就可以用到上面的 join 知识了。当然,使用循环也可以做。
1 2 3 4 5 6 7 8 9 10 |
list = ['a','b',123] val = '' for v in list: if isinstance(v, str): val += '\'{}\''.format(v) else: val += str(v) val += ',' val = val.strip(',') |
两种方式的效果是一样的。
四、enumerate 和 zip
将字符串作为参数传入 enumerate() 和 zip() 函数,生成相应的 enumerate 型的对象和 zip 型的对象,然后我们在通过循环将这些对象按照我们的需要输出即可。比如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
# enumerate >>> for i, e in enumerate("abcd"): ... print(i, e) ... 0 a 1 b 2 c 3 d # zip >>> for i in zip("abcd", "1234"): ... print(i) ... ('a', '1') ('b', '2') ('c', '3') ('d', '4') |
这样的函数能为我们提供更加便捷的处理数据的方法。比如 enumerate 可以得到元素索引位置,那么我们就可以利用 enumerate 来做排序了。
五、字符串转为表达式
有时候我们可能需要拼接字符串后直接能把这字符串转换为表达式,可调用执行,就可以用 eval 函数来处理。eval 是 Python 的一个内置函数,这个函数的作用是,返回传入字符串的表达式的结果。想象一下变量赋值时,将等号右边的表达式写成字符串的格式,将这个字符串作为 eval 的参数,eval 的返回值就是这个表达式的结果。
Python 中 eval 函数的用法十分的灵活,但也十分危险,安全性是其最大的缺点。
举个例子感受一下 eval 的强大:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
>>> a = "[1, 2, 3]" >>> eval(a) [1, 2, 3] >>> type(eval(a)) <class 'list'> >>> b = eval(a) >>> b.append(4) >>> b [1, 2, 3, 4] |
强大吧,给个字符串给 eval,eval 给你一个表达式返回值。
eval 的语法格式如下:
1 |
eval(expression[, globals[, locals]]) |
expression:字符串。
globals:变量作用域,全局命名空间,如果被提供,则必须是一个字典对象。
locals:变量作用域,局部命名空间,如果被提供,可以是任何映射对象。
结合 globals 和 locals 看看几个例子,传递 globals 参数值为 {“age”: 1822},
1 2 |
>>> eval("{'name': 'linux','age': age}", {"age": 1822}) {'name': 'linux', 'age': 1822} |
再加上 locals 变量:
1 2 3 4 |
>>> age = 18 >>> eval("{'name': 'linux','age': age}", {"age": 1822}, locals()) {'name': 'linux', 'age': 18} |
根据上面两个例子可以看到当 locals 参数为空,globals 参数不为空时,查找 globals 参数中是否存在变量,并计算。
当两个参数都不为空时,先查找 locals 参数,再查找 globals 参数,locals 参数中同名变量会覆盖 globals 中的变量。
eval 虽然方便,但是要注意安全性,可以将字符串转成表达式并执行,就可以利用执行系统命令,删除文件等操作。
假设用户恶意输入。比如:
1 |
eval("__import__('os').system('rm -fr /tmp/')") |
直接可以执行所有有权限的系统命令了,所以使用 eval,一方面享受他的了灵活性同时,也要注意安全性。