首页 » Python编程快速上手 » Python编程快速上手全文在线阅读

《Python编程快速上手》第6章 字符串操作

关灯直达底部

文本是程序需要处理的最常见的数据形式。你已经知道如何用+操作符连接两个字符串,但能做的事情还要多得多。可以从字符串中提取部分字符串,添加或删除空白字符,将字母转换成小写或大写,检查字符串的格式是否正确。你甚至可以编写Python代码访问剪贴板,复制或粘贴文本。

在本章中,你将学习所有这些内容和更多内容。然后你会看到两个不同的编程项目:一个是简单的口令管理器,另一个将枯燥的文本格式化工作自动化。

6.1 处理字符串

让我们来看看,Python提供的写入、打印和访问字符串的一些方法。

6.1.1 字符串字面量

在Python中输入字符串值相当简单的:它们以单引号开始和结束。但是如何才能在字符串内使用单引号呢?输入'That is Alice's cat.'是不行的,因为Python认为这个字符串在Alice之后就结束了,剩下的(s cat.')是无效的Python代码。好在,有几种方法来输入字符串。

6.1.2 双引号

字符串可以用双引号开始和结束,就像用单引号一样。使用双引号的一个好处,就是字符串中可以使用单引号字符。在交互式环境中输入以下代码:

>>> spam = "That is Alice's cat."  

因为字符串以双引号开始,所以Python知道单引号是字符串的一部分,而不是表示字符串的结束。但是,如果在字符串中既需要使用单引号又需要使用双引号,那就要使用转义字符。

6.1.3 转义字符

“转义字符”让你输入一些字符,它们用其他方式是不可能放在字符串里的。转义字符包含一个倒斜杠(/),紧跟着是想要添加到字符串中的字符。(尽管它包含两个字符,但大家公认它是一个转义字符。)例如,单引号的转义字符是/’。你可以在单引号开始和结束的字符串中使用它。为了看看转义字符的效果,在交互式环境中输入以下代码:

>>> spam = 'Say hi to Bob/'s mother.'  

Python知道,因为Bob/'s中的单引号有一个倒斜杠,所以它不是表示字符串结束的单引号。转义字符/'和/"让你能在字符串中加入单引号和双引号。

表6-1列出了可用的转义字符。

表6-1 转义字符

转义字符

打印为

/'

单引号

/"

双引号

/t

制表符

/n

换行符

//

倒斜杠

在交互式环境中输入以下代码:

>>> print("Hello there!/nHow are you?/nI/'m doing fine.")Hello there!How are you?I'm doing fine.  

6.1.4 原始字符串

可以在字符串开始的引号之前加上r,使它成为原始字符串。“原始字符串”完全忽略所有的转义字符,打印出字符串中所有的倒斜杠。例如,在交互式环境中输入以下代码:

>>> print(r'That is Carol/'s cat.')That is Carol/'s cat.  

因为这是原始字符串,Python认为倒斜杠是字符串的一部分,而不是转义字符的开始。如果输入的字符串包含许多倒斜杠,比如下一章中要介绍的正则表达式字符串,那么原始字符串就很有用。

6.1.5 用三重引号的多行字符串

虽然可以用/n转义字符将换行放入一个字符串,但使用多行字符串通常更容易。在Python中,多行字符串的起止是3个单引号或3个双引号。“三重引号”之间的所有引号、制表符或换行,都被认为是字符串的一部分。Python的代码块缩进规则不适用于多行字符串。

打开文件编辑器,输入以下代码:

print('''Dear Alice,Eve's cat has been arrested for catnapping, cat burglary, and extortion.Sincerely,Bob''')  

将该程序保存为catnapping.py并运行。输出看起来像这样:

Dear Alice,Eve's cat has been arrested for catnapping, cat burglary, and extortion.Sincerely,Bob  

请注意,Eve's中的单引号字符不需要转义。在原始字符串中,转义单引号和双引号是可选的。下面的print调用将打印出同样的文本,但没有使用多行字符串:

print('Dear Alice,/n/nEve/'s cat has been arrested for catnapping, catburglary, and extortion./n/nSincerely,/nBob')  

6.1.6 多行注释

虽然井号字符(#)表示这一行是注释,但多行字符串常常用作多行注释。下面是完全有效的Python代码:

"""This is a test Python program.Written by Al Sweigart [email protected] program was designed for Python 3, not Python 2."""def spam:    """This is a multiline comment to help    explain what the spam function does."""    print('Hello!')  

6.1.7 字符串下标和切片

字符串像列表一样,使用下标和切片。可以将字符串'Hello world!'看成是一个列表,字符串中的每个字符都是一个表项,有对应的下标。

'  H  e  l  l  o  w  o  r  l  d   !   '    0  1  2  3  4  5  6  7  8  9  10 11  

字符计数包含了空格和感叹号,所以'Hello world!'有12个字符,H的下标是0,!的下标是11。在交互式环境中输入以下代码:

>>> spam = 'Hello world!'>>> spam[0]'H'>>> spam[4]'o'>>> spam[-1]'!'>>> spam[0:5]'Hello'>>> spam[:5]'Hello'>>> spam[6:]'world!'  

如果指定一个下标,你将得到字符串在该处的字符。如果用一个下标和另一个下标指定一个范围,开始下标将被包含,结束下标则不包含。因此,如果spam是'Hello world!',spam[0:5]就是'Hello'。通过spam[0:5]得到的子字符串,将包含spam[0]到spam[4]的全部内容,而不包括下标5处的空格。

请注意,字符串切片并没有修改原来的字符串。可以从一个变量中获取切片,记录在另一个变量中。在交互式环境中输入以下代码:

>>> spam = 'Hello world!'>>> fizz = spam[0:5]>>> fizz'Hello'  

通过切片并将结果子字符串保存在另一个变量中,就可以同时拥有完整的字符串和子字符串,便于快速简单的访问。

6.1.8 字符串的in和not in操作符

像列表一样,in和not in操作符也可以用于字符串。用in或not in连接两个字符串得到的表达式,将求值为布尔值True或False。在交互式环境中输入以下代码:

>>> 'Hello' in 'Hello World'True>>> 'Hello' in 'Hello'True>>> 'HELLO' in 'Hello World'False>>> '' in 'spam'True>>> 'cats' not in 'cats and dogs'False  

这些表达式测试第一个字符串(精确匹配,区分大小写)是否在第二个字符串中。

6.2 有用的字符串方法

一些字符串方法会分析字符串,或生成转变过的字符串。本节介绍了这些方法,你会经常使用它们。

6.2.1 字符串方法upper、lower、isupper和islower

upper和lower字符串方法返回一个新字符串,其中原字符串的所有字母都被相应地转换为大写或小写。字符串中非字母字符保持不变。

在交互式环境中输入以下代码:

>>> spam = 'Hello world!'>>> spam = spam.upper>>> spam'HELLO WORLD!'>>> spam = spam.lower>>> spam'hello world!'  

请注意,这些方法没有改变字符串本身,而是返回一个新字符串。如果你希望改变原来的字符串,就必须在该字符串上调用upper或lower,然后将这个新字符串赋给保存原来字符串的变量。这就是为什么必须使用 spam = spam.upper,才能改变spam中的字符串,而不是仅仅使用spam.upper(这就好比,如果变量eggs中包含值10,写下eggs + 3并不会改变eggs的值,但是eggs = eggs + 3会改变eggs的值)。

如果需要进行大小写无关的比较,upper和lower方法就很有用。字符串'great'和'GREat'彼此不相等。但在下面的小程序中,用户输入Great、GREAT或grEAT都没关系,因为字符串首先被转换成小写。

print('How are you?')feeling = inputif feeling.lower == 'great':    print('I feel great too.')else:    print('I hope the rest of your day is good.')  

在运行该程序时,先显示问题,然后输入变形的great,如GREat,程序将给出输出I feel great too。在程序中加入代码,处理多种用户输入情况或输入错误,诸如大小写不一致,这会让程序更容易使用,且更不容易失效。

How are you?GREatI feel great too.  

如果字符串至少有一个字母,并且所有字母都是大写或小写,isupper和islower方法就会相应地返回布尔值True。否则,该方法返回False。在交互式环境中输入以下代码,并注意每个方法调用的返回值:

>>> spam = 'Hello world!'>>> spam.islowerFalse>>> spam.isupperFalse>>> 'HELLO'.isupperTrue>>> 'abc12345'.islowerTrue>>> '12345'.islowerFalse>>> '12345'.isupperFalse  

因为upper和lower字符串方法本身返回字符串,所以也可以在“那些”返回的字符串上继续调用字符串方法。这样做的表达式看起来就像方法调用链。在交互式环境中输入以下代码:

>>> 'Hello'.upper'HELLO'>>> 'Hello'.upper.lower'hello'>>> 'Hello'.upper.lower.upper'HELLO'>>> 'HELLO'.lower'hello'>>> 'HELLO'.lower.islowerTrue  

6.2.2 isX字符串方法

除了islower和isupper,还有几个字符串方法,它们的名字以is开始。这些方法返回一个布尔值,描述了字符串的特点。下面是一些常用的isX字符串方法:

  • isalpha返回True,如果字符串只包含字母,并且非空;
  • isalnum返回True,如果字符串只包含字母和数字,并且非空;
  • isdecimal返回True,如果字符串只包含数字字符,并且非空;
  • isspace返回True,如果字符串只包含空格、制表符和换行,并且非空;
  • .istitle返回True,如果字符串仅包含以大写字母开头、后面都是小写字母的单词。

在交互式环境中输入以下代码:

>>> 'hello'.isalphaTrue>>> 'hello123'.isalphaFalse>>> 'hello123'.isalnumTrue>>> 'hello'.isalnumTrue>>> '123'.isdecimalTrue>>> ' '.isspaceTrue>>> 'This Is Title Case'.istitleTrue>>> 'This Is Title Case 123'.istitleTrue>>> 'This Is not Title Case'.istitleFalse>>> 'This Is NOT Title Case Either'.istitleFalse  

如果需要验证用户输入,isX字符串方法是有用的。例如,下面的程序反复询问用户年龄和口令,直到他们提供有效的输入。打开一个新的文件编辑器窗口,输入以下程序,保存为validateInput.py:

while True:    print('Enter your age:')    age = input    if age.isdecimal:break    print('Please enter a number for your age.')while True:    print('Select a new password (letters and numbers only):')    password = input    if password.isalnum:break    print('Passwords can only have letters and numbers.')  

在第一个while循环中,我们要求用户输入年龄,并将输入保存在age中。如果age是有效的值(数字),我们就跳出第一个while循环,转向第二个循环,询问口令。否则,我们告诉用户需要输入数字,并再次要求他们输入年龄。在第二个while循环中,我们要求输入口令,客户的输入保存在password中。如果输入是字母或数字,就跳出循环。如果不是,我们并不满意,于是告诉用户口令必须是字母或数字,并再次要求他们输入口令。

如果运行,该程序的输出看起来如下:

Enter your age:forty twoPlease enter a number for your age.Enter your age:42Select a new password (letters and numbers only):secr3t!Passwords can only have letters and numbers.Select a new password (letters and numbers only):secr3t  

在变量上调用isdecimal和isalnum,我们就能够测试保存在这些变量中的值是否为数字,是否为字母或数字。这里,这些测试帮助我们拒绝输入forty two,接受42,拒绝secr3t!,接受secr3t。

6.2.3 字符串方法startswith和endswith

startswith和endswith方法返回True,如果它们所调用的字符串以该方法传入的字符串开始或结束。否则,方法返回False。在交互式环境中输入以下代码:

>>> 'Hello world!'.startswith('Hello')True>>> 'Hello world!'.endswith('world!')True>>> 'abc123'.startswith('abcdef')False>>> 'abc123'.endswith('12')False>>> 'Hello world!'.startswith('Hello world!')True>>> 'Hello world!'.endswith('Hello world!')True  

如果只需要检查字符串的开始或结束部分是否等于另一个字符串,而不是整个字符串,这些方法就可以替代等于操作符==,这很有用。

6.2.4 字符串方法join和split

如果有一个字符串列表,需要将它们连接起来,成为一个单独的字符串,join方法就很有用。join方法在一个字符串上调用,参数是一个字符串列表,返回一个字符串。返回的字符串由传入的列表中每个字符串连接而成。例如,在交互式环境中输入以下代码:

>>> ', '.join(['cats', 'rats', 'bats'])'cats, rats, bats'>>> ' '.join(['My', 'name', 'is', 'Simon'])'My name is Simon'>>> 'ABC'.join(['My', 'name', 'is', 'Simon'])'MyABCnameABCisABCSimon'  

请注意,调用join方法的字符串,被插入到列表参数中每个字符串的中间。例如,如果在', '字符串上调用join(['cats', 'rats', 'bats']),返回的字符串就是'cats, rats, bats'。

要记住,join方法是针对一个字符串而调用的,并且传入一个列表值(很容易不小心用其他的方式调用它)。split方法做的事情正好相反:它针对一个字符串调用,返回一个字符串列表。在交互式环境中输入以下代码:

>>> 'My name is Simon'.split['My', 'name', 'is', 'Simon']  

默认情况下,字符串'My name is Simon'按照各种空白字符分割,诸如空格、制表符或换行符。这些空白字符不包含在返回列表的字符串中。也可以向split方法传入一个分割字符串,指定它按照不同的字符串分割。例如,在交互式环境中输入以下代码:

>>> 'MyABCnameABCisABCSimon'.split('ABC')['My', 'name', 'is', 'Simon']>>> 'My name is Simon'.split('m')['My na', 'e is Si', 'on']  

一个常见的split用法,是按照换行符分割多行字符串。在交互式环境中输入以下代码:

>>> spam = '''Dear Alice,How have you been? I am fine.There is a container in the fridgethat is labeled "Milk Experiment". Please do not drink it.Sincerely,Bob'''>>> spam.split('/n')['Dear Alice,', 'How have you been? I am fine.', 'There is a container in thefridge', 'that is labeled "Milk Experiment".', '', 'Please do not drink it.','Sincerely,', 'Bob']  

向split方法传入参数’/n’,我们按照换行符分割变量中存储的多行字符串,返回列表中的每个表项,对应于字符串中的一行。

6.2.5 用rjust、ljust和center方法对齐文本

rjust和ljust字符串方法返回调用它们的字符串的填充版本,通过插入空格来对齐文本。这两个方法的第一个参数是一个整数长度,用于对齐字符串。在交互式环境中输入以下代码:

>>> 'Hello'.rjust(10)'      Hello'>>> 'Hello'.rjust(20)'   Hello'>>> 'Hello World'.rjust(20)'   Hello World'>>> 'Hello'.ljust(10)'Hello      '  

'Hello'.rjust(10)是说我们希望右对齐,将'Hello'放在一个长度为10的字符串中。'Hello'有5个字符,所以左边会加上5个空格,得到一个10个字符的字符串,实现'Hello'右对齐。

rjust和ljust方法的第二个可选参数将指定一个填充字符,取代空格字符。在交互式环境中输入以下代码:

>>> 'Hello'.rjust(20, '*')'***************Hello'>>> 'Hello'.ljust(20, '-')'Hello---------------'  

center字符串方法与ljust与rjust类似,但它让文本居中,而不是左对齐或右对齐。在交互式环境中输入以下代码:

>>> 'Hello'.center(20)'       Hello '>>> 'Hello'.center(20, '=')'=======Hello========'  

如果需要打印表格式数据,留出正确的空格,这些方法就特别有用。打开一个新的文件编辑器窗口,输入以下代码,并保存为picnicTable.py:

def printPicnic(itemsDict, leftWidth, rightWidth):    print('PICNIC ITEMS'.center(leftWidth + rightWidth, '-'))    for k, v in itemsDict.items:print(k.ljust(leftWidth, '.') + str(v).rjust(rightWidth))picnicItems = {'sandwiches': 4, 'apples': 12, 'cups': 4, 'cookies': 8000}printPicnic(picnicItems, 12, 5)printPicnic(picnicItems, 20, 6)  

在这个程序中,我们定义了printPicnic方法,它接受一个信息的字典,并利用center、ljust和rjust,以一种干净对齐的表格形式显示这些信息。

我们传递给printPicnic的字典是picnicItems。在picnicItems中,我们有4个三明治、12个苹果、4个杯子和8000块饼干。我们希望将这些信息组织成两行,表项的名字在左边,数量在右边。

要做到这一点,就需要决定左列和右列的宽度。与字典一起,我们将这些值传递给printPicnic。

printPicnic接受一个字典,一个leftWidth表示表的左列宽度,一个rightWidth表示表的右列宽度。它打印出标题PICNIC ITEMS,在表上方居中。然后它遍历字典,每行打印一个键-值对。键左对齐,填充句号。值右对齐,填充空格。

在定义printPicnic后,我们定义了字典picnicItems,并调用printPicnic两次,传入不同的表左右列宽度。

运行该程序,野餐用品就会显示两次。第一次左列宽度是12个字符,右列宽度是5个字符。第二次它们分别是20个和6个字符。

---PICNIC ITEMS--sandwiches.. 4apples...... 12cups........ 4cookies..... 8000-------PICNIC ITEMS-------sandwiches.......... 4apples.............. 12cups................ 4cookies............. 8000  

利用rjust、ljust和center让你确保字符串整齐对齐,即使你不清楚字符串有多少字符。

6.2.6 用strip、rstrip和lstrip删除空白字符

有时候你希望删除字符串左边、右边或两边的空白字符(空格、制表符和换行符)。strip字符串方法将返回一个新的字符串,它的开头或末尾都没有空白字符。lstrip和rstrip方法将相应删除左边或右边的空白字符。

在交互式环境中输入以下代码:

>>> spam = ' Hello World '>>> spam.strip'Hello World'>>> spam.lstrip'Hello World '>>> spam.rstrip'     Hello World'  

有一个可选的字符串参数,指定两边的哪些字符应该删除。在交互式环境中输入以下代码:

>>> spam = 'SpamSpamBaconSpamEggsSpamSpam'>>> spam.strip('ampS')'BaconSpamEggs'  

向strip方法传入参数'ampS',告诉它在变量中存储的字符串两端,删除出现的a、m、p和大写的S。传入strip方法的字符串中,字符的顺序并不重要:strip('ampS')做的事情和strip('mapS')或strip('Spam')一样。

6.2.7 用pyperclip模块拷贝粘贴字符串

pyperclip模块有copy和paste函数,可以向计算机的剪贴板发送文本,或从它接收文本。将程序的输出发送到剪贴板,使它很容易粘贴到邮件、文字处理程序或其他软件中。pyperclip模块不是Python自带的。要安装它,请遵从附录A中安装第三方模块的指南。安装pyperclip模块后,在交互式环境中输入以下代码:

>>> import pyperclip>>> pyperclip.copy('Hello world!')>>> pyperclip.paste'Hello world!'  

当然,如果你的程序之外的某个程序改变了剪贴板的内容,paste函数就会返回它。例如,如果我将这句话复制到剪贴板,然后调用paste,看起来就会像这样:

>>> pyperclip.paste'For example, if I copied this sentence to the clipboard and then calledpaste, it would look like this:'  

在IDLE之外运行Python脚本

到目前为止,你一直在使用IDLE中的交互式环境和文件编辑器来运行Python脚本。但是,你不想每次运行一个脚本时,都打开IDLE和Python脚本,这样不方便。好在,有一些快捷方式,让你更容易地建立和运行Python脚本。这些步骤在Windows、OS X和Linux上稍有不同,但每一种都在附录B中描述。请翻到附录B,学习如何方便地运行Python脚本,并能够向它们传递命令行参数。(使用IDLE时,不能向程序传递命令行参数。)

6.3 项目:口令保管箱

你可能在许多不同网站上拥有账号,每个账号使用相同的口令是个坏习惯。如果这些网站中任何一个有安全漏洞,黑客就会知道你所有的其他账号的口令。最好是在你的计算机上,使用口令管理器软件,利用一个主控口令,解锁口令管理器。然后将某个账户口令拷贝到剪贴板,再将它粘贴到网站的口令输入框。

你在这个例子中创建的口令管理器程序并不安全,但它基本展示了这种程序的工作原理。

本章项目

这是本书的第一个章内项目。以后,每章都会有一些项目,展示该章介绍的一些概念。这些项目的编写方式,让你从一个空白的文件编辑器窗口开始,得到一个完整的、能工作的程序。就像交互式环境的例子一样,不要只看项目的部分,要注意计算机的提示!

第1步:程序设计和数据结构

你希望用一个命令行参数来运行这个程序,该参数是账号的名称。例如,账号的口令将拷贝到剪贴板,这样用户就能将它粘贴到口令输入框。通过这种方式,用户可以有很长而复杂的口令,又不需要记住它们。

打开一个新的文件编辑器窗口,将该程序保存为pw.py。程序开始时需要有一行#!(参见附录B),并且应该写一些注释,简单描述该程序。因为你希望关联每个账号的名称及其口令,所以可以将这些作为字符串保存在字典中。字典将是组织你的账号和口令数据的数据结构。让你的程序看起来像下面这样:

#! python3# pw.py - An insecure password locker program.PASSWORDS = {'email': 'F7minlBDDuvMJuxESSKHFhTxFtjVB6',     'blog': 'VmALvQyKAxiVH5G8v01if1MLZF3sdt',     'luggage': '12345'}  

第2步:处理命令行参数

命令行参数将存储在变量sys.argv中(关于如何在程序中使用命令行参数,更多信息请参见附录B)。sys.argv列表中的第一项总是一个字符串,它包含程序的文件名('pw.py')。第二项应该是第一个命令行参数。对于这个程序,这个参数就是账户名称,你希望获取它的口令。因为命令行参数是必须的,所以如果用户忘记添加参数(也就是说,如果列表中少于两个值),你就显示用法信息。让你的程序看起来像下面这样:

#! python3# pw.py - An insecure password locker program.PASSWORDS = {'email': 'F7minlBDDuvMJuxESSKHFhTxFtjVB6',     'blog': 'VmALvQyKAxiVH5G8v01if1MLZF3sdt',     'luggage': '12345'}import sysif len(sys.argv) < 2:    print('Usage: python pw.py [account] - copy account password')    sys.exit account = sys.argv[1] # first command line arg is the account name  

第3步:复制正确的口令

既然账户名称已经作为字符串保存在变量account中,你就需要看看它是不是PASSWORDS字典中的键。如果是,你希望利用pyperclip.copy,将该键的值复制到剪贴板(既然用到了pyperclip模块,就需要导入它)。请注意,实际上不需要account变量,你可以在程序中所有使用account的地方,直接使用sys.argv[1]。但名为account的变量更可读,不像是神秘的sys.argv[1]。

让你的程序看起来像这样:

#! python3# pw.py - An insecure password locker program.PASSWORDS = {'email': 'F7minlBDDuvMJuxESSKHFhTxFtjVB6',     'blog': 'VmALvQyKAxiVH5G8v01if1MLZF3sdt',     'luggage': '12345'}import sys, pyperclipif len(sys.argv) < 2:    print('Usage: py pw.py [account] - copy account password')    sys.exitaccount = sys.argv[1] # first command line arg is the account nameif account in PASSWORDS:    pyperclip.copy(PASSWORDS[account])    print('Password for ' + account + ' copied to clipboard.')else:    print('There is no account named ' + account)  

这段新代码在PASSWORDS字典中查找账户名称。如果该账号名称是字典中的键,我们就取得该键对应的值,将它复制到剪贴板,然后打印一条消息,说我们已经复制了该值。否则,我们打印一条消息,说没有这个名称的账号。

这就是完整的脚本。利用附录B中的指导,轻松地启动命令行程序,现在你就有了一种快速的方式,将账号的口令复制到剪贴板。如果需要更新口令,就必须修改源代码的PASSWORDS字典中的值。

当然,你可能不希望把所有的口令都放在一个地方,让某人能够轻易地复制。但你可以修改这个程序,利用它快速地将普通文本复制到剪贴板。假设你需要发出一些电子邮件,它们有许多同样的段落。你可以将每个段落作为一个值,放在PASSWORDS字典中(此时你可能希望对这个字典重命名),然后你就有了一种方式,快速地选择一些标准的文本,并复制到剪贴板。

在Windows上,你可以创建一个批处理文件,利用Win-R运行窗口,来运行这个程序(关于批处理文件的更多信息,参见附录B)。在文件编辑器中输入以下代码,保存为pw.bat,放在C:/Windows目录下:

@py.exe C:/Python34/pw.py %*@pause  

有了这个批处理文件,在Windows上运行口令保存程序,就只要按下Win-R,再输入pw <account name>。

6.4 项目:在Wiki标记中添加无序列表

在编辑一篇维基百科的文章时,你可以创建一个无序列表,即让每个列表项占据一行,并在前面放置一个星号。但是假设你有一个非常大的列表,希望添加前面的星号。你可以在每一行开始处输入这些星号,一行接一行。或者也可以用一小段Python脚本,将这个任务自动化。

bulletPointAdder.py脚本将从剪贴板中取得文本,在每一行开始处加上星号和空格,然后将这段新的文本贴回到剪贴板。例如,如果我将下面的文本复制到剪贴板(取自于维基百科的文章“List of Lists of Lists”):

Lists of animalsLists of aquarium lifeLists of biologists by author abbreviationLists of cultivars  

然后运行bulletPointAdder.py程序,剪贴板中就会包含下面的内容:

* Lists of animals* Lists of aquarium life* Lists of biologists by author abbreviation* Lists of cultivars  

这段前面加了星号的文本,就可以粘贴回维基百科的文章中,成为一个无序列表。

第1步:从剪贴板中复制和粘贴

你希望bulletPointAdder.py程序完成下列事情:

1.从剪贴板粘贴文本;

2.对它做一些处理;

3.将新的文本复制到剪贴板。

第2步有一点技巧,但第1步和第3步相当简单,它们只是利用了pyperclip.copy和pyperclip.paste函数。现在,我们先写出程序中第1步和第3步的部分。输入以下代码,将程序保存为bulletPointAdder.py:

#! python3# bulletPointAdder.py - Adds Wikipedia bullet points to the start# of each line of text on the clipboard.import pypercliptext = pyperclip.paste# TODO: Separate lines and add stars.pyperclip.copy(text)  

TODO注释是提醒,你最后应该完成这部分程序。下一步实际上就是实现程序的这个部分。

第2步:分离文本中的行,并添加星号

调用pyperclip.paste将返回剪贴板上的所有文本,结果是一个大字符串。如果我们使用“List of Lists of Lists”的例子,保存在text中的字符串就像这样:

'Lists of animals/nLists of aquarium life/nLists of biologists by authorabbreviation/nLists of cultivars'  

在打印到剪贴板,或从剪贴板粘贴时,该字符串中的/n换行字符,让它能显示为多行。在这一个字符串中有许多“行”。你想要在每一行开始处添加一个星号。

你可以编写代码,查找字符串中每个/n换行字符,然后在它后面添加一个星号。但更容易的做法是,使用split方法得到一个字符串的列表,其中每个表项就是原来字符串中的一行,然后在列表中每个字符串前面添加星号。

让程序看起来像这样:

#! python3# bulletPointAdder.py - Adds Wikipedia bullet points to the start# of each line of text on the clipboard.import pypercliptext = pyperclip.paste# Separate lines and add stars.lines = text.split('/n')for i in range(len(lines)): # loop through all indexes in the "lines" list    lines[i] = '* ' + lines[i] # add star to each string in "lines" list pyperclip.copy(text)  

我们按换行符分割文本,得到一个列表,其中每个表项是文本中的一行。我们将列表保存在lines中,然后遍历lines中的每个表项。对于每一行,我们在开始处添加一个新号和一个空格。现在lines中的每个字符串都以星号开始。

第3步:连接修改过的行

lines列表现在包含修改过的行,每行都以星号开始。但pyperclip.copy需要一个字符串,而不是字符串的列表。要得到这个字符串,就要将lines传递给join方法,连接列表中字符串。让你的程序看起来像这样:

#! python3# bulletPointAdder.py - Adds Wikipedia bullet points to the start# of each line of text on the clipboard.import pypercliptext = pyperclip.paste# Separate lines and add stars.lines = text.split('/n')for i in range(len(lines)): # loop through all indexes for "lines" list    lines[i] = '* ' + lines[i] # add star to each string in "lines" listtext = '/n'.join(lines)pyperclip.copy(text)  

运行这个程序,它将取代剪贴板上的文本,新的文本每一行都以星号开始。现在程序完成了,可以在剪贴板中复制一些文本,试着运行它。

即使不需要自动化这样一个专门的任务,也可能想要自动化某些其他类型的文本操作,诸如删除每行末尾的空格,或将文本转换成大写或小写。不论你的需求是什么,都可以使用剪贴板作为输入和输出。

6.5 小结

文本是常见的数据形式,Python自带了许多有用的字符串方法,来处理保存在字符串中的文本。在你写的几乎每个Python程序中,都会用到取下标、切片和字符串方法。

现在你写的程序似乎不太复杂,因为它们没有图形用户界面,没有图像和彩色的文本。到目前为止,你在利用print显示文本,利用input让用户输入文本。但是,用户可以通过剪贴板,快速输入大量的文本。这种能力提供了一种有用的编程方式,可以操作大量的文本。这些基于文本的程序可能没有闪亮的窗口或图形,但它们能很快完成大量有用的工作。

操作大量文本的另一种方式,是直接从硬盘读写文件。在下一章中,你将学习如何用Python来做到这一点。

6.6 习题

1.什么是转义字符?

2.转义字符/n和/t代表什么?

3.如何在字符串中放入一个倒斜杠字符/?

4.字符串"Howl's Moving Castle"是有效字符串。为什么单词中的单引号没有转义,却没有问题?

5.如果你不希望在字符串中加入/n,怎样写一个带有换行的字符串?

6.下面的表达式求值为什么?

  • 'Hello world!'[1]

  • 'Hello world!'[0:5]

  • 'Hello world!'[:5]

  • 'Hello world!'[3:]

7.下面的表达式求值为什么?

  • 'Hello'.upper

  • 'Hello'.upper.isupper

  • 'Hello'.upper.lower

8.下面的表达式求值为什么?

  • 'Remember, remember, the fifth of November.'.split

  • '-'.join('There can be only one.'.split)

9.什么字符串方法能用于字符串右对齐、左对齐和居中?

10.如何去掉字符串开始或末尾的空白字符?

6.7 实践项目

作为实践,编程完成下列任务。

表格打印

编写一个名为printTable的函数,它接受字符串的列表的列表,将它显示在组织良好的表格中,每列右对齐。假定所有内层列表都包含同样数目的字符串。例如,该值可能看起来像这样:

tableData = [['apples', 'oranges', 'cherries', 'banana'],     ['Alice', 'Bob', 'Carol', 'David'],     ['dogs', 'cats', 'moose', 'goose']]  

你的printTable函数将打印出:

  apples Alice dogs oranges Bob    catscherries Carol moose  banana David goose  

提示

你的代码首先必须找到每个内层列表中最长的字符串,这样整列就有足够的宽度以放下所有字符串。你可以将每一列的最大宽度,保存为一个整数的列表。printTable函数的开始可以是colWidths = [0] * len(tableData),这创建了一个列表,它包含了一些0,数目与tableData中内层列表的数目相同。这样,colWidths[0]就可以保存tableData[0]中最长字符串的宽度,colWidths[1]就可以保存tableData[1]中最长字符串的宽度,以此类推。然后可以找到colWidths列表中最大的值,决定将什么整数宽度传递给rjust字符串方法。