Python a-t-il une fonction intégrée pour désindenter une chaîne multiligne?

Dites que j'ai la chaîne

s = """
    Controller = require 'controller'

    class foo
        view: 'baz'
        class: 'bar'

        constructor: ->
            Controller.mix @
"""

Chaque ligne de la chaîne a maintenant une indentation globale de 4 espaces. Si cette chaîne était déclarée dans une fonction, elle aurait une indentation globale de 8 espaces, etc.

Python a-t-il une fonction pour supprimer l'indentation gauche globale de la chaîne?

Je voudrais que cette sortie de fonction soit:

Controller = require 'controller'

class foo
    view: 'baz'
    class: 'bar'

    constructor: ->
        Controller.mix @"
38
demandé sur dreftymac 2012-06-22 17:23:13

2 réponses

Pas une fonction intégrée, mais une fonction de la bibliothèque standard: textwrap.dedent()

>>> print(textwrap.dedent(s))

Controller = require 'controller'

class foo
    view: 'baz'
    class: 'bar'

    constructor: ->
        Controller.mix @
69
répondu Sven Marnach 2012-06-22 13:24:35

textwrap.dedent() est proche de ce que vous voulez, mais il ne met pas en œuvre ce que vous avez demandé, car il a une nouvelle ligne principale. Vous pouvez soit envelopper dedent dans une fonction qui supprime le saut de ligne de s:

def my_dedent(string):
    if string and string[0] == '\n':
        string = string[1:]
    return textwrap.dedent(string)

Cependant textwrap.dedent() gère les lignes avec juste des espaces de manière spéciale, ce qui est correct si vous générez une source Python à partir d'une instruction multiligne indentée, où les espaces de fin sont insignifiants.

, Mais en général, il est inapproprié que textwrap.dedent() supprime les espaces superflus à partir des lignes avec plus d'espaces que le "retrait maximum", supprime les espaces de toutes les lignes d'espaces et supprime tout espace avant la fermeture """, d'autant plus que ce comportement est non documenté et fait avec des expressions régulières non transparentes.

Comme je génère également du code source non-Python où les espaces sont souvent significatifs, j'utilise la routine suivante. Il ne gère pas L'indentation des onglets, mais il vous donne la sortie que vous avez demandée sans diriger retour à la ligne, où textwrap.dedent() échoue.

def remove_leading_spaces(s, strict=False):
    '''Remove the maximum common spaces from all non-empty lines in string

Typically used to remove leading spaces from all non-empty lines in a
multiline string, preserving all extra spaces.
A leading newline (when not useing '"""\') is removed unless the strict
argument is True.

Note that if you want two spaces on the last line of the return value 
without a newline, you have to use the max indentation + 2 spaces before 
the closing """. If you just input 2 spaces that is likely to be the 
maximum indent.
    '''
    if s and not strict and s[0] == '\n':
        s = s[1:]
    lines = s.splitlines(True) # keep ends
    max_spaces = -1
    for line in lines:
        if line != '\n':
            for idx, c in enumerate(line[:max_spaces]):
                if not c == ' ':
                    break
            max_spaces = idx + 1
    return ''.join([l if l == '\n' else l[max_spaces-1:] for l in lines])
7
répondu Anthon 2013-03-17 12:55:09