Recipe1.14.Changing the Indentation of a Multiline String


Recipe 1.14. Changing the Indentation of a Multiline String

Credit: Tom Good

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.

Solution

The methods of string objects are quite handy, and let us write a simple function to perform this task:

def reindent(s, numSpaces):     leading_space = numSpaces * ' '     lines = [ leading_space + line.strip( )               for line in s.splitlines( ) ]     return '\n'.join(lines)

Discussion

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

>>> 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

Even if the lines in s are initially indented differently, this recipe makes their indentation homogeneous, which 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 difficult for either positive or negative values of the adjustment. However, negative values need a check to ensure that no nonspace characters 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:

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( ) ])

All of these functions rely on the string method splitlines, which is similar to a split on '\n'. splitlines has the extra ability to leave the trailing newline on each line (when you call it with true as its argument). Sometimes this turns out to be handy: addSpaces could not be quite as short and sweet without this ability of the splitlines string method.

Here's how we can combine these functions to build another function to delete just enough leading spaces from each line to ensure that the least-indented line of the block becomes flush left, while preserving the relative indentation of the lines:

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

See Also

Library Reference and Python in a Nutshell docs on sequence types.



Python Cookbook
Python Cookbook
ISBN: 0596007973
EAN: 2147483647
Year: 2004
Pages: 420

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net