文章来自《Python cookbook》.

翻译仅仅是为了个人学习,其它商业版权纠纷与此无关!

-- 0.706 [2004-09-14 17:40:58]

1. Changing the Indentation of a Multiline String 改变多行字符串的缩进

Credit: Tom Good

1.1. 问题 Problem

You have a string made up of multiple lines, and you need to build another string from it, adding or removing leading spaces on each line so that the indentation of each line is some absolute number of spaces.

你有一个由多行组成的字符串,你需要从它构造另一个新的字符串,增加或移去每一行的前导空格,使得每一行的缩进由确定数量的空格组成。

1.2. 解决 Solution

We don't need re for this. The string module (or string methods, in Python 2.0 and later) is quite sufficient:

这里,我们不需要re。string模块(或Python2.0或以后版本中的string方法)就足够了:

   1 import string
   2 def reindent(s, numSpaces):
   3     s = string.split(s, '\n')
   4     s = [(numSpaces * ' ') + string.lstrip(line) for line in s]
   5     s = string.join(s, '\n')
   6     return s

1.3. 讨论 Discussion

When working with text, it may be necessary to change the indentation level of a block. This recipe's code takes a multiline string and adds or removes leading spaces on each line so that the indentation level of each line of the block matches some absolute number of spaces. For example:

在处理文本时,可能需要改变一个文本块的缩进。这个配方中的代码,把一个多行字符串增加或移去每一行的前导空格,使得每一行的缩进级别与确定数量的空格匹配。例如:

   1 >>> x = """line one
   2 ... line two
   3 ... and line three
   4 ... """
   5 >>> print x
   6 line one
   7 line two
   8 and line three
   9 
  10 >>> print reindent(x, 8)
  11         line one
  12         line two
  13         and line three

Even if the lines in s are initially indented differently, this recipe makes their indentation homogeneous. This is sometimes what we want, and sometimes not. A frequent need is to adjust the amount of leading spaces in each line, so that the relative indentation of each line in the block is preserved. This is not hard either, for either positive or negative values of the adjustment. However, negative values need a check to ensure that no nonspaces are snipped from the start of the lines. Thus, we may as well split the functionality into two functions to perform the transformations, plus one to measure the number of leading spaces of each line and return the result as a list:

既使各行原先的缩进不同,这个配方也会使它们的缩近变得一致。这有时是我们想要的,有时不是。一个频繁的需要是调整每一行前导空格的数量,使得文本块中的每一行之间的相对缩进保持不变。这也不困难,无论调整量是正值还是负值。可是,调整量是负值时要检查,确认没有非空白字符从行首被剪掉。这样,为了完成转换,我们还是把这个功能分到两个函数中(去实现)要好点.再增加一个函数用来测量每行的前导空格,用一个列表返回结果。

   1 def addSpaces(s, numAdd):
   2     white = " "*numAdd
   3     return white + white.join(s.splitlines(1))
   4 
   5 def delSpaces(s, numDel):
   6     def aux(line, numDel=numDel, white=" "*numDel):
   7         if line[:numDel] != white:
   8             raise ValueError, "removing more spaces than there are!"
   9         return line[numDel:]
  10     return ''.join(map(aux, s.splitlines(1)))
  11 
  12 def numSpaces(s):
  13     return [len(line)-len(line.lstrip()) for line in s.splitlines(  )]

This alternative approach relies on the string method splitlines (and so requires Python 2.0 or later,like any other recipe using string methods and/or list comprehensions), which is similar to a split on '\n', with the extra ability to leave the trailing newline on each line when called with a true argument. This is not often crucial (the last statement in delSpaces, for example, might just as easily return '\n'.join(map(aux, s.split('\n')))), but sometimes it turns out to be (addSpaces could not be quite as short and sweet without this ability of the splitlines string method).

这个可选方法依赖于string方法splitlines(因此需要Python 2.0 及以后版本,象其它使用string方法和/或列表内涵的配方一样),它近似于用'\n'调用split。通常,不是非得用splitlines取代split(如delSpaces的最后语句,可以只是简单的 return '\n'.join(map(aux, s.split('\n')) ),但有时它会变得很必要(函数addSpaces 如果不使用string的splitlines方法,就不会如此短小可爱)。

For example, here's how we can combine these functions to build another function that deletes enough leading spaces from each line to ensure that the least-indented line of the block becomes flush-left,while preserving the relative indentations of all the other lines:

例如,这里(演示了)我们怎样把这些函数结合起来,构成另一个函数,用来从每行删除足够的前导空格,使得块中缩进最小的行变得紧靠左边,而保留所有其余行的相对缩进:

   1 def unIndentBlock(s):
   2     return delSpaces(s, min(numSpaces(s)))

1.4. 参考 See Also

The Library Reference section on sequence types.