本节书摘来自异步社区《Python Cookbook(第2版)中文版》一书中的第1章,第1.14节,作者[美]Alex Martelli , Anna Martelli Ravenscrof , David Ascher ,高铁军 译,更多章节内容可以访问云栖社区“异步社区”公众号查看。
1.14 改变多行文本字符串的缩进
任务
有个包含多行文本的字符串,需要创建该字符串的一个拷贝,并在每行行首添加或者删除一些空格,以保证每行的缩进都是指定数目的空格数。
解决方案
字符串对象已经提供了趁手的工具,我们只需写个简单的函数即可满足需求:
def reindent(s, numSpaces):
leading_space = numSpaces * ' '
lines = [ leading_space + line.strip( )
for line in s.splitlines( ) ]
return '\n'.join(lines)
讨论
处理文本的时候,我们常常需要改变一块文本的缩进。“解决方案”给出的代码,在多行文本的每行行首增减了空格,这样每行开头都有相同的空格数。比如:
>>> x = """ line one
... line two
... and line three
... """
>>> print x
line one
line two
and line three
>>> print reindent(x, 4)
line one
line two
and line three
即使每行的缩进都截然不同,该函数仍能够使它们的缩进变得完全一致,这有时正是我们所需要的,但有时却不是。一个常见的需求是,调整每行行首的空格数,并确保整块文本的行之间的相对缩进不发生变化。无论是正向还是反向调整,这都不是难事。不过,反向调整需要检查一下每行行首的空格,以确保不会把非空格字符截去。因此,我们需要将这个任务分解,用两个函数来完成转化,再加上一个计算每行行首空格并返回一个列表的函数:
def addSpaces(s, numAdd):
white = " "*numAdd
return white + white.join(s.splitlines(True))
def numSpaces(s):
return [len(line)-len(line.lstrip( )) for line in s.splitlines( )]
def delSpaces(s, numDel):
if numDel > min(numSpaces(s)):
raise ValueError, "removing more spaces than there are!"
return '\n'.join([ line[numDel:] for line in s.splitlines( ) ])
所有这些函数都依赖字符串的方法splitlines,它和根据’n’来切分的split很相似。不过splitlines还有额外的好处,它保留了每行末尾的换行符(当你传入的参数是True的时候)。有时这非常方便:如果splitlines这个字符串方法没有提供这个能力,addSpaces不可能这么短小精悍。
然后,我们用这些函数组合成另一个函数来删除行首空格。该函数可以在保持各行之间的相对缩进不变的情况下,只删除它能够删除的空格,让缩进最小的行与左端边界平齐。
def unIndentBlock(s):
return delSpaces(s, min(numSpaces(s)))
更多资料
Library Reference和Python in a Nutshell中关于序列类型的部分。