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.

1voto

Sam Watkins Points 1299

Je voulais conserver exactement ce qui se trouve entre les lignes entre guillemets, en supprimant uniquement le retrait commun. J'ai constaté que texwrap.dedent y inspect.cleandoc ne l'a pas fait tout à fait bien, alors j'ai écrit celui-ci. Il utilise os.path.commonprefix .

import re
from os.path import commonprefix

def ql(s, eol=True):
    lines = s.splitlines()
    l0 = None
    if lines:
        l0 = lines.pop(0) or None
    common = commonprefix(lines)
    indent = re.match(r'\s*', common)[0]
    n = len(indent)
    lines2 = [l[n:] for l in lines]
    if not eol and lines2 and not lines2[-1]:
        lines2.pop()
    if l0 is not None:
        lines2.insert(0, l0)
    s2 = "\n".join(lines2)
    return s2

Cela peut citer n'importe quelle chaîne de caractères avec n'importe quelle indentation. Je voulais qu'il inclue la nouvelle ligne de fin par défaut, mais avec une option pour l'enlever afin qu'il puisse citer n'importe quelle chaîne proprement.

Exemple :

print(ql("""
     Hello
    |\---/|
    | o_o |
     \_^_/
    """))

print(ql("""
         World
        |\---/|
        | o_o |
         \_^_/
    """))

La deuxième chaîne a 4 espaces d'indentation commune parce que la dernière chaîne de caractères """ est moins en retrait que le texte cité :

 Hello
|\---/|
| o_o |
 \_^_/

     World
    |\---/|
    | o_o |
     \_^_/

Je pensais que ce serait plus simple, sinon je n'aurais pas pris la peine de le faire !

0voto

Mark Points 1219

J'ai eu un problème similaire : Je voulais que ma chaîne entre guillemets soit indentée, mais je ne voulais pas que la chaîne ait tous ces espaces au début de chaque ligne. J'ai utilisé re pour corriger mon problème :

        print(re.sub('\n *','\n', f"""Content-Type: multipart/mixed; boundary="===============9004758485092194316=="
`           MIME-Version: 1.0
            Subject: Get the reader's attention here!
            To: recipient@email.com

            --===============9004758485092194316==
            Content-Type: text/html; charset="us-ascii"
            MIME-Version: 1.0
            Content-Transfer-Encoding: 7bit

            Very important message goes here - you can even use <b>HTML</b>.
            --===============9004758485092194316==--
        """))

Ci-dessus, j'ai pu garder mon code indenté, mais la chaîne de caractères est restée essentiellement coupée. Tous les espaces au début de chaque ligne ont été supprimés. C'était important car tout espace devant les lignes spécifiques SMTP ou MIME briserait le message électronique.

Le compromis que j'ai fait est que j'ai laissé la Content-Type sur la première ligne parce que le regex que j'utilisais n'a pas supprimé l'initiale \n (qui a cassé l'email). Si cela me dérangeait suffisamment, je suppose que j'aurais pu ajouter un lstrip comme celui-ci :

print(re.sub('\n *','\n', f"""
    Content-Type: ...
""").lstrip()

Après avoir lu cette page vieille de 10 ans, j'ai décidé de m'en tenir à re.sub puisque je n'ai pas vraiment compris toutes les nuances de textwrap y inspect .

-1voto

Kostia Points 1

Il existe un moyen beaucoup plus simple :

    foo = """first line\
             \nsecond line"""

-15voto

FlorianH Points 1722

Si j'ai bien compris, vous prenez ce que l'utilisateur saisit, vous l'indentez correctement et vous l'ajoutez au reste de votre programme (puis vous exécutez l'ensemble du programme).

Ainsi, après avoir introduit l'entrée de l'utilisateur dans votre programme, vous pouvez exécuter une expression rationnelle, qui reprend l'indentation forcée. Quelque chose comme : Entre trois guillemets, remplacer tous les "nouveaux marqueurs de ligne" suivis de quatre espaces (ou d'une tabulation) par un seul "nouveau marqueur de ligne".

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