首页 > 技术文章 > 5.1.2 字符串常用方法

avention 2018-04-07 00:18 原文

1 find()、rfind()、index()、rindex()、count()

  find()和rfind()方法分别用来查找一个字符串在另一个字符串指定范围(默认是整个字符串)中首次和最后一次出现的位置,如果不存在则返回-1;

  index()和rindex()方法用来返回一个字符串在另一个字符串指定范围首次和最后一次出现的位置,如果不存在则抛出异常;

  count()方法用来返回一个字符串在另一个字符串中出现的次数,如果不存在则返回0。

 1 >>> s = 'apple,peach,banana,peach,pear'
 2 >>> s.find('peach')  #返回第一次出现的位置
 3 6
 4 >>> s.find('peach',7)   #从指定位置开始查找
 5 19
 6 >>> s.find('peach',7,20)  #从指定范围中进行查找,找不到则返回-1
 7 -1
 8 >>> 
 9 >>> s.rfind('p')     #从字符串尾部向前查找
10 25
11 >>> 
12 >>> s.index('p')   #返回首次出现的位置
13 1
14 >>> 
15 >>> s.index('pe')
16 6
17 >>> s.index('pear')
18 25
19 >>> 
20 >>> s.index('ppp')   #指定字符串不存在时抛出异常
21 Traceback (most recent call last):
22   File "<pyshell#100>", line 1, in <module>
23     s.index('ppp')   #指定字符串不存在时抛出异常
24 ValueError: substring not found
25 >>> 
26 >>> s.count('p')
27 5
28 >>> 
29 >>> s.count('ppp')    #不存在时返回0
30 0
31 >>> 

  拓展知识:实际开发时应优先考虑使用Python内置函数和内置对象的方法,运行速度快,并且运行稳定。例如,下面的代码用来检查长字符串中哪些位置上的字母是a。比较使用find()的速度和逐个字符比较的快慢。

 1 from string import ascii_letters
 2 from random import choice
 3 from time import time
 4 
 5 #构造一个很长很长的字符串
 6 letters = ''.join([choice(ascii_letters) for i in range(999999)])
 7 
 8 #使用字符串的find()方法
 9 def positions_of_charactor(sentence,ch):
10     result = []
11     index=0
12     index=sentence.find(ch,index+1)
13     while index != -1:
14         result.append(index)
15         index=sentence.find(ch,index+1)
16     return result
17 
18 #普通方法,逐个字符比较
19 def demo(s,c):
20     result=[]
21     for i,ch in enumerate(s):
22         if ch == c:
23             result.append(i)
24     return result
25 
26 start = time()
27 positions = positions_of_charactor(letters,'a')
28 print(time() - start)   #0.009000539779663086
29 
30 start = time()
31 p=demo(letters,'a')
32 print(time()-start)    #0.09600567817687988

 

2 split()、rsplit()、partition()、rpartition()

  split() 和 rsplit()方法分别用来指定字符为分隔字符,从字符串左端开始和右端开始将其分隔成多个字符串,并返回包含分隔结果的列表;

  partition() 和 rpartition()用来以指定字符串为分隔符将原字符串分隔为3部分,即分隔符之前的字符串、分隔符字符串和分隔符之后的字符串,如果指定的分隔符不在原字符串中,则返回原字符串和两个空字符串。

 1 >>> s = 'apple,peach,banana,pear'
 2 >>> li = s.split(',')    #使用逗号进行分割
 3 >>> li
 4 ['apple', 'peach', 'banana', 'pear']
 5 >>> 
 6 >>> ll = s.rsplit(',')
 7 >>> ll
 8 ['apple', 'peach', 'banana', 'pear']
 9 >>> 
10 >>> 
11 >>> #从左侧使用逗号进行切分
12 >>> s.partition(',')
13 ('apple', ',', 'peach,banana,pear')
14 >>> 
15 >>> #从右侧使用逗号进行切分
16 >>> s.rpartition(',')
17 ('apple,peach,banana', ',', 'pear')
18 >>> 
19 >>> #使用字符串作为分隔符
20 >>> s.partition('banana')
21 ('apple,peach,', 'banana', ',pear')
22 >>> 
23 >>> s = '2017-10-31'
24 >>> t = s.split('-')
25 >>> t
26 ['2017', '10', '31']
27 >>> list(map(int,t))
28 [2017, 10, 31]
29 >>> 

  对于split() 和 rsplit()方法,如果不指定分隔符,则字符串中的任何空白符号(包括空格、换行符、制表符等)的连续出现都将被认为是分隔符,返回包含最终分隔结果的列表。

1 >>> s = 'hello world \n\n My name is Done   '
2 >>> s.split()
3 ['hello', 'world', 'My', 'name', 'is', 'Done']
4 >>> 
5 
6 #如果明确指定分隔符,则这些空白字符就不会被忽略了。

 

3 join()

  与split() 相反,join()方法用来将列表中多个字符串进行连接,并在相邻两个字符串之间插入指定字符。

 1 >>> li = ['apple', 'peach', 'banana', 'pear']
 2 >>> sep = ","
 3 >>> s = sep.join(li)
 4 >>> #使用逗号作为连接符
 5 >>> s
 6 'apple,peach,banana,pear'
 7 >>> 
 8 >>> #使用冒号作为连接符
 9 >>> ':'.join(li)
10 'apple:peach:banana:pear'
11 >>> 
12 >>> #使用空字符串作为连接符
13 >>> ''.join(li)
14 'applepeachbananapear'
15 >>> 

 

  小技巧:使用split() 和 join() 方法可以删除字符串中多余的空白字符,如果有连续多个空白字符,只保留一个,例如:

 1 >>> x = 'aaa        bb     c d e    fff     '
 2 >>> l = x.split()
 3 >>> l
 4 ['aaa', 'bb', 'c', 'd', 'e', 'fff']
 5 >>> 
 6 >>> ' '.join(l)
 7 'aaa bb c d e fff'
 8 >>> 
 9 
10 # 判断两个字符串在Python意义上是否等价
11 def equavilent(s1,s2):
12     if s1 == s2:
13         return True
14     elif ' '.join(s1.split()) == ' '.join(s2.split()):
15         return True
16     elif ''.join(s1.split()) == ''.join(s2.split()):
17         return True
18     else:
19         return False
20 
21 print(equavilent('pip list','pip   list'))   #True

 

  注意:使用运算符“+”也可以连接字符串,但该运算符涉及大量数据的复制,效率非常低,不适合大量长字符串的连接。

  拓展知识:timeit模块还支持下面代码演示的用法,从运行结果可以看出,当需要对大量数据进行类型转换时,内置函数map()可以提供非常高的效率。

 1 >>> import timeit
 2 >>> timeit.timeit('"-".join(str(n) for n in range(100))' ,number = 100000)
 3 3.3937918491848773
 4 >>> 
 5 >>> timeit.timeit('"-".join([str(n) for n in range(100)])',number = 100000)
 6 3.0601289909394467
 7 >>> 
 8 >>> timeit.timeit('"-".join(map(str,range(100)))',number = 100000)
 9 2.22682740585347
10 >>> 

 

4 lower()、upper()、capitalize()、title()、swapcase()

  这几个方法分别用来将字符串转换为小写、大写字符串、将字符串首字母变为大写,将每个单词的首字母变为大写以及大小写互换,这几个方法都是生成新字符串,并不对原字符串做任何修改。

 1 >>> s = 'What is Your Name?'
 2 >>> 
 3 >>> #返回小写字符串
 4 >>> s.lower()
 5 'what is your name?'
 6 >>> 
 7 >>> #返回大写字符串
 8 >>> s.upper()
 9 'WHAT IS YOUR NAME?'
10 >>> 
11 >>> #字符串首字符大写
12 >>> s.capitalize()
13 'What is your name?'
14 >>> 
15 >>> #每个单词的首字母大写
16 >>> s.title()
17 'What Is Your Name?'
18 >>> 
19 >>> #字符串中,大小写互换,大写变小写,小写变大写
20 >>> s.swapcase()
21 'wHAT IS yOUR nAME?'
22 >>> 

 

5 replace()

  该方法用来替换字符串中指定字符或子字符串的所有重复出现,每次只能替换一个字符或一个字符串,类似于Word、WPS、记事本等文本编辑器的查找与替换功能。该方法并不修改原字符串,而是返回一个新字符串。

 1 >>> s = '中国,中国'
 2 >>> s
 3 '中国,中国'
 4 >>> 
 5 >>> s.replace('中国','中华人民共和国')
 6 '中华人民共和国,中华人民共和国'
 7 >>> s
 8 '中国,中国'
 9 >>> 
10 >>> 'abcdabc'.replace('abc','ABC')
11 'ABCdABC'
12 >>> 

 

6 maketrans()、translate()

  maketrans()方法用来生成字符映射表,而translate() 方法则按映射表中定义的对应关系转换字符串并替换其中的字符,使用这两个方法的组合可以同时处理多个不同的字符,replace()方法则无法满足这一要求。下面的代码演示这两个方法的用法,当然也可以定义自己的字符映射表,然而用来对字符串进行加密。

 1 >>> #创建映射表,将字符"abcdef123"一一对应地转换为"uvwxyz@#$"
 2 >>> table = ''.maketrans('bacdef123','uvwxyz@#$')
 3 >>> 
 4 >>> #创建原始字符串
 5 
 6 >>> s = 'Python is a greate programming language. I like it!'
 7 >>> 
 8 >>> s.translate(table)
 9 'Python is v gryvty progrvmming lvnguvgy. I liky it!'
10 >>> 
11 
12 >>> #下面的代码模拟了凯撒加密算法
13 >>> #每个英文字母替换为字母表中后面第3个字母,当然,3也可以是其他数字
14 >>> import string
15 >>> #小写英文字母
16 >>> lowerLetters = string.ascii_lowercase
17 >>> #大写英文字母
18 >>> upperLetters = string.ascii_uppercase
19 >>> #英文字母
20 >>> before = lowerLetters + upperLetters
21 >>> before
22 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
23 >>> 
24 >>> #循环位移
25 >>> after = lowerLetters[3:] + lowerLetters[:3] + upperLetters[3:] + upperLetters[:3]
26 >>> after
27 'defghijklmnopqrstuvwxyzabcDEFGHIJKLMNOPQRSTUVWXYZABC'
28 >>> 
29 >>> table = ''.maketrans(before,after)
30 >>> 
31 >>> s = 'If the implementation is easy to explain, it may be a good idea.'
32 >>> s.translate(table)
33 'Li wkh lpsohphqwdwlrq lv hdvb wr hasodlq, lw pdb eh d jrrg lghd.'
34 >>> 

  

  拓展知识:Python标准库中的string提供了英文字母大小写,数字字符,标点符号等常量,可以直接使用,下面的代码实现了随机密码生成功能。

 1 >>> import string
 2 >>> x = string.digits + string.ascii_letters + string.punctuation
 3 >>> x
 4 '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~'
 5 >>> 
 6 >>> import random
 7 >>> 
 8 >>> #从x 中随机选择8个字符作为密码
 9 >>> ''.join([random.choice(x) for i in range(8)])
10 '7=_G--7R'
11 >>> 
12 >>> ''.join([random.choice(x) for i in range(8)])
13 "'*R?!jxO"
14 >>> 
15 >>> ''.join([random.choice(x) for i in range(8)])
16 '"JI6nyk$'
17 >>> 
18 >>> ''.join([random.choice(x) for i in range(8)])
19 'DbB~<nSP'
20 >>> 

 

  拓展知识:在Python中,字符串属于不可变对象,不支持原地修改,如果需要修改其中的值,只能重新创建一个新的字符串对象。然而,如果确实需要一个支持原地修改的unicode数据对象,可以使用io.StringIO对象或array模块。

 

7 strip()、rstrip()、lstrip()

  这几个方法分别用来删除两端、右端或左端连续的空白字符或指定字符。

 1 >>> s = ' abc   '
 2 >>> #删除空白字符
 3 >>> s2 = s.strip()
 4 >>> s
 5 ' abc   '
 6 >>> 
 7 >>> s2 = s.strip()
 8 >>> s
 9 ' abc   '
10 >>> 
11 >>> s = " abc   "
12 >>> s.strip()     #删除空白字符
13 'abc'
14 >>> 
15 >>> '\n\nhello world   \n\n'.strip()
16 'hello world'
17 >>> 
18 >>> "aaaaaaaaddfff".strip("a")     #删除指定字符串
19 'ddfff'
20 >>> 
21 >>> "aaaaasasssddfaa".rstrip("a")  #删除字符串右端指定字符
22 'aaaaasasssddf'
23 >>> 
24 >>> "aaaassddfaaa".lstrip("a")   #删除字符串左端指定字符
25 'ssddfaaa'
26 >>> 

 

  

  注意:这3个函数的参数指定的字符串并不作为一个整体对待,而是在原字符串的两侧、右侧、左侧删除参数字符串中包含的所有字符,例如:

 1 >>> 'aabbccddeeeffg'.strip('af')  #字母f不在字符串两侧,所以不删除
 2 'bbccddeeeffg'
 3 >>> 
 4 >>> 'aabbccddeeeffg'.strip('gaf')
 5 'bbccddeee'
 6 >>> 
 7 >>> 'aabbccddeeeffg'.strip('gbaef')
 8 'ccdd'
 9 >>> 
10 >>> 'aabbccddeeeffg'.strip('gbaefcd')
11 ''
12 >>> 

 

8 eval()

  内置函数eval()用来把任意字符串转化为Python表达式并进行求值。

 1 >>> eval('3 + 4')   #计算表达式的值
 2 7
 3 >>> a = 3
 4 >>> b = 5
 5 >>> eval('a+b')     #这时候要求变量a和b已存在
 6 8
 7 >>> 
 8 >>> import math
 9 >>> eval('help(math.sqrt)')
10 Help on built-in function sqrt in module math:
11 
12 sqrt(...)
13     sqrt(x)
14     
15     Return the square root of x.
16 
17 >>> 
18 >>> eval('aa')   #当前作用域中不存在 aa ,抛出异常
19 Traceback (most recent call last):
20   File "<pyshell#225>", line 1, in <module>
21     eval('aa')   #当前作用域中不存在 aa ,抛出异常
22   File "<string>", line 1, in <module>
23 NameError: name 'aa' is not defined
24 >>> 

  

  在Python 3.x中,input()将用户的输入一律按字符串对待,如果需要将其还原为本来的类型,可以使用内置函数eval(),有时候可能需要配合异常处理结构。

 1 >>> x = input()
 2 357
 3 >>> x
 4 '357'
 5 >>> 
 6 >>> eval(x)
 7 357
 8 >>> 
 9 >>> x = input()
10 [3,5,7]
11 >>> 
12 >>> eval(x)   #注意这里不能使用list(x)进行转换
13 [3, 5, 7]
14 >>> 
15 >>> x = input()
16 abc
17 >>> x
18 'abc'
19 >>> eval(x)
20 Traceback (most recent call last):
21   File "<pyshell#242>", line 1, in <module>
22     eval(x)
23   File "<string>", line 1, in <module>
24 NameError: name 'abc' is not defined
25 >>> 
26 >>> #当前作用域中不存在变量 abc
27 try:
28     print(eval(x))
29 except:
30     print('wrong input')
31 
32 #wrong input

 

9 关键字 in

  与列表、元组、字典、集合一样,也可以使用关键字in和not in来判断一个字符串是否出现在另一个字符串中,返回True或False。

 

1 >>> 'a' in 'abcde'   #测试一个字符串是否存在于另一个字符串中
2 True
3 >>> 
4 >>> 'ac' in 'abcde'
5 False
6 >>> 
7 >>> #in关键字左边的字符串作为一个整体对待
8 >>> 

 

  几乎所有论坛或社区都会对用户提交的输入进行检查,并过滤一些非法的敏感词,这极大地促进了网络文明。这样的功能实际上就可以使用关键字in来实现,例如:下面的代码用来检测用户输入中是否有不允许的敏感词,如果有就提示非法,否则提示正常。

1 words = ('测试','非法','暴利')
2 text = input('请输入:')
3 print(text)
4 for word in words:
5     if word in text:
6         print('非法')
7         break
8     else:
9         print('正常')

 

  下面的代码则可以用来测试用户输入中是否有敏感词,如果有就把敏感词替换为3个星号 *** 。

1 words = ('测试','非法','暴利','')
2 text = '这句话里含有非法的内容'
3 for word in words:
4     if word in text:
5         text = text.replace(word,'***')
6 
7 print(text)  #这句***里含有***的内容

 

10 startswith()、endswith()

  这两个方法用来判断字符串是否以指定字符串开始或结束,可以接受两个整数参数来限定字符串的监测范围,例如:

 1 >>> s = 'Beautiful is better than ugly.'
 2 >>> 
 3 >>> #监测整个字符串
 4 >>> s.startswith('Be')
 5 True
 6 >>> 
 7 >>> #指定监测范围的起始位置
 8 >>> s.startswith('Be',5)
 9 False
10 >>> 
11 >>> #指定监测范围的起始位置和结束位置
12 >>> s.startswith('Be',0,5)
13 True
14 >>> 

  

  另外,这两个方法还可以接收一个字符串元组作为参数来表示前缀或后缀,例如,下面的代码可以列出指定文件夹下所有扩展名为bmp、jpg或gif的图片。

1 import os
2 a = [filename for filename in os.listdir(r'D:\\') if filename.endswith(('.bmp','.jpg','gif'))]
3 print(a)
4 
5 #['新建文本文档.gif']

 

11 isalnum()、isalpha()、isdigit()、isdecimal()、isnumeric()、isspace()、isupper()、islower()

  用来测试字符串是否为数字或字母、是否为字母、是否为数字、是否为空白字符、是否为大写字母以及是否为小写字母。

 1 >>> '1234abcd'.isalnum()
 2 True
 3 >>> 
 4 >>> #全部为英文字母时返回True
 5 >>> '1234abcd'.isalpha()
 6 False
 7 >>> 
 8 >>> #全部为数字时返回True
 9 >>> '1234abcd'.isdigit()
10 False
11 >>> 
12 >>> 'abcd'.isalpha()
13 True
14 >>> 
15 >>> '1234.0'.isdigit()
16 False
17 >>> '1234'.isdigit()
18 True
19 >>> 
20 >>> ''.isnumeric()    #isnumeric()支持汉字数字
21 True
22 >>> 
23 >>> ''.isdecimal()
24 False
25 >>> #isdecimal()还支持罗马数字

 

  Python标准库unicodedata提供了不同形式数字字符到十进制数字的转换方法。

1 >>> import unicodedata
2 >>> unicodedata.numeric('2')
3 2.0
4 >>> 
5 >>> unicodedata.numeric('')
6 9.0
7 
8 #还支持罗马数字

 

12 center()、ljust()、rjust()、zfill()

  center()、ljust()、rjust()返回指定宽度的新字符串,原字符串居中、左对齐或右对齐出现在新字符串中,如果指定的宽度大于字符串长度,则使用指定的字符进行填充,默认以空格进行填充。zfill()返回指定宽度的字符串,在左侧以字符0进行填充。

 1 >>> 'Hello world!'.center(20)    #居中对齐,以空格进行填充
 2 '    Hello world!    '
 3 >>> 'Hello world!'.center(20,'=') #居中对齐,以字符"="进行填充
 4 '====Hello world!===='
 5 >>> 
 6 >>> 'Hello world!'.ljust(20,'=')  #左对齐
 7 'Hello world!========'
 8 >>> 
 9 >>> 'Hello world!'.rjust(20,'=')  #右对齐
10 '========Hello world!'
11 >>> 
12 >>> 'abc'.zfill(5)                #在左侧填充数字字符0
13 '00abc'
14 >>> 
15 >>> 'abc'.zfill(2)                #指定宽度小于字符串长度时,返回字符串本身
16 'abc'
17 >>> 
18 >>> 'uio'.zfill(20)
19 '00000000000000000uio'
20 >>> 

 

  拓展知识:Python标准库textwrap提供了更加友好的排版函数。

>>> import textwrap
>>> #Python之禅
>>> doc='''Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!'''
>>> 
>>> #按指定宽度进行排版
>>> print(textwrap.fill(doc,width=20))
Beautiful is better
than ugly. Explicit
is better than
implicit. Simple is
better than complex.
Complex is better
than complicated.
Flat is better than
nested. Sparse is
better than dense.
Readability counts.
Special cases aren't
special enough to
break the rules.
Although
practicality beats
purity. Errors
should never pass
silently. Unless
explicitly silenced.
In the face of
ambiguity, refuse
the temptation to
guess. There should
be one-- and
preferably only one
--obvious way to do
it. Although that
way may not be
obvious at first
unless you're Dutch.
Now is better than
never. Although
never is often
better than *right*
now. If the
implementation is
hard to explain,
it's a bad idea. If
the implementation
is easy to explain,
it may be a good
idea. Namespaces are
one honking great
idea -- let's do
more of those!
>>> 
>>> #默认宽度最大为70
>>> import pprint
>>> pprint.pprint(textwrap.wrap(doc))
['Beautiful is better than ugly. Explicit is better than implicit.',
 'Simple is better than complex. Complex is better than complicated.',
 'Flat is better than nested. Sparse is better than dense. Readability',
 "counts. Special cases aren't special enough to break the rules.",
 'Although practicality beats purity. Errors should never pass silently.',
 'Unless explicitly silenced. In the face of ambiguity, refuse the',
 'temptation to guess. There should be one-- and preferably only one',
 '--obvious way to do it. Although that way may not be obvious at first',
 "unless you're Dutch. Now is better than never. Although never is often",
 'better than *right* now. If the implementation is hard to explain,',
 "it's a bad idea. If the implementation is easy to explain, it may be a",
 "good idea. Namespaces are one honking great idea -- let's do more of",
 'those!']
>>> 

 

13 内置函数、切片

  除了字符串对象提供的方法以外,很多Python内置函数也可以对字符串进行操作,例如:

 1 >>> x = 'Hello world.'
 2 >>> len(x)   #字符串长度
 3 12
 4 >>> 
 5 >>> max(x)   #最大字符
 6 'w'
 7 >>> min(x)
 8 ' '
 9 >>> #zip() 也可以作用于字符串
10 >>> list(zip(x,x))
11 [('H', 'H'), ('e', 'e'), ('l', 'l'), ('l', 'l'), ('o', 'o'), (' ', ' '), ('w', 'w'), ('o', 'o'), 
   ('r', 'r'), ('l', 'l'), ('d', 'd'), ('.', '.')] 12 >>> 13 >>> #切片也适用于字符串,但仅限于读取其中的元素,不支持字符串修改。 14 >>> 'Explicit is better than implicit.'[:8] 15 'Explicit' 16 >>> 17 >>> 'Explicit is better than implicit.'[9:23] 18 'is better than' 19 >>> 20 >>> #另外,运算符“+” 和 “*”也支持字符串之间或者字符串与整数的运算。

推荐阅读