89 votes

Comment supprimer l'indentation supplémentaire des chaînes de caractères multi-lignes Python à triple citation ?

J'ai un éditeur python où l'utilisateur entre un script ou du code, qui est ensuite placé dans une méthode principale en coulisse, tout en ayant également chaque ligne indentée. Le problème est que si un utilisateur a une chaîne de plusieurs lignes, l'indentation faite à l'ensemble du script affecte la chaîne, en insérant une tabulation dans chaque espace. Un script problématique serait quelque chose d'aussi simple que :

"""foo
bar
foo2"""

Ainsi, dans la méthode principale, cela ressemblerait à ceci :

def main():
    """foo
    bar
    foo2"""

et la chaîne aurait maintenant une tabulation supplémentaire au début de chaque ligne.

145voto

thraxil Points 1681

textwrap.dedent de la bibliothèque standard est là pour annuler automatiquement l'indentation farfelue.

63voto

bbenne10 Points 1203

D'après ce que je vois, une meilleure réponse ici pourrait être inspect.cleandoc qui fait une grande partie de ce que textwrap.dedent mais corrige également les problèmes que textwrap.dedent a avec la ligne de tête.

L'exemple ci-dessous montre les différences :

>>> import textwrap
>>> import inspect
>>> x = """foo bar
    baz
    foobar
    foobaz
    """
>>> inspect.cleandoc(x)
'foo bar\nbaz\nfoobar\nfoobaz'
>>> textwrap.dedent(x)
'foo bar\n    baz\n    foobar\n    foobaz\n'
>>> y = """
...     foo
...     bar
... """
>>> inspect.cleandoc(y)
'foo\nbar'
>>> textwrap.dedent(y)
'\nfoo\nbar\n'
>>> z = """\tfoo
bar\tbaz
"""
>>> inspect.cleandoc(z)
'foo\nbar     baz'
>>> textwrap.dedent(z)
'\tfoo\nbar\tbaz\n'

Notez que inspect.cleandoc transforme également les tabulations internes en espaces. Cela peut ne pas convenir à votre cas d'utilisation, mais cela fonctionne bien pour moi.

20voto

IfLoop Points 59461

Ce qui suit la première ligne d'une chaîne multiligne fait partie de la chaîne et n'est pas traité comme une indentation par l'analyseur. Vous pouvez écrire librement :

def main():
    """foo
bar
foo2"""
    pass

et il fera ce qu'il faut.

D'un autre côté, ce n'est pas lisible, et Python le sait. Ainsi, si une docstring contient des espaces dans sa section deuxième cette quantité d'espace est supprimée lorsque vous utilisez la fonction help() pour voir la docstring. Ainsi, help(main) et l'image ci-dessous help(main2) produisent les mêmes informations d'aide.

def main2():
    """foo
    bar
    foo2"""
    pass

2voto

codeforester Points 17582

Montrer la différence entre textwrap.dedent y inspect.cleandoc avec un peu plus de clarté :

Comportement avec la partie avant non indentée

import textwrap
import inspect

string1="""String
with
no indentation
       """
string2="""String
        with
        indentation
       """
print('string1 plain=' + repr(string1))
print('string1 inspect.cleandoc=' + repr(inspect.cleandoc(string1)))
print('string1 texwrap.dedent=' + repr(textwrap.dedent(string1)))
print('string2 plain=' + repr(string2))
print('string2 inspect.cleandoc=' + repr(inspect.cleandoc(string2)))
print('string2 texwrap.dedent=' + repr(textwrap.dedent(string2)))

Sortie

string1 plain='String\nwith\nno indentation\n       '
string1 inspect.cleandoc='String\nwith\nno indentation\n       '
string1 texwrap.dedent='String\nwith\nno indentation\n'
string2 plain='String\n        with\n        indentation\n       '
string2 inspect.cleandoc='String\nwith\nindentation'
string2 texwrap.dedent='String\n        with\n        indentation\n'

Comportement avec la partie avant en retrait

string1="""
String
with
no indentation
       """
string2="""
        String
        with
        indentation
       """

print('string1 plain=' + repr(string1))
print('string1 inspect.cleandoc=' + repr(inspect.cleandoc(string1)))
print('string1 texwrap.dedent=' + repr(textwrap.dedent(string1)))
print('string2 plain=' + repr(string2))
print('string2 inspect.cleandoc=' + repr(inspect.cleandoc(string2)))
print('string2 texwrap.dedent=' + repr(textwrap.dedent(string2)))

Sortie

string1 plain='\nString\nwith\nno indentation\n       '
string1 inspect.cleandoc='String\nwith\nno indentation\n       '
string1 texwrap.dedent='\nString\nwith\nno indentation\n'
string2 plain='\n        String\n        with\n        indentation\n       '
string2 inspect.cleandoc='String\nwith\nindentation'
string2 texwrap.dedent='\nString\nwith\nindentation\n'

1voto

Mihail Points 1559

Le seul moyen que je vois est de supprimer les n premières tabulations pour chaque ligne commençant par la deuxième, où n est l'identification connue de la méthode principale.

Si l'identification n'est pas connue à l'avance, vous pouvez ajouter un saut de ligne avant de l'insérer et enlever le nombre de tabulations de la dernière ligne...

La troisième solution consiste à analyser les données et à trouver le début d'une citation multiligne et à ne pas ajouter votre identification à chaque ligne suivante jusqu'à ce qu'elle soit fermée.

Je pense qu'il y a une meilleure solution

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X