web-dev-qa-db-fra.com

formatage de chaînes multi-lignes en python

Pour commencer, je cherche à obtenir une sortie désirée comme ceci:

*********************************************************************
                                 hello
********************************************************************* 

Pour ce faire, j'ai assigné le sortie désirée à une variable avec une chaîne multiligne et je l'ai imprimé avec le format.

$ cat varibale.py 
decorator = """ **********************************************************************
                               {}
            ********************************************************************** """
print(decorator.format("hello"))

Sortie:

**********************************************************************
                               hello
            **********************************************************************

Le problème avec l'approche ci-dessus est le espaces supplémentaires dans la troisième ligne de sortie qui semble étrange.

Je suis capable d'y parvenir de la manière suivante:

$ cat varibale.py 
decorator = """ **********************************************************************
                             {}
********************************************************************* 
"""
print(decorator.format("hello"))

Sortie: 

 **********************************************************************
                             hello
********************************************************************* 

Mais de cette façon, mon code n’a pas l’air beau, car il ne suit pas l’indentation.

Veuillez suggérer le bon moyen d’atteindre le résultat souhaité.

5
Here_2_learn

Une façon de rendre les chaînes littérales multilignes jolies consiste à utiliser une barre oblique inverse pour échapper à la nouvelle ligne, comme ceci:

s = '''\
*********************************************************************
                                 hello
*********************************************************************
'''
print(s)

sortie

*********************************************************************
                                 hello
*********************************************************************

Cependant, PEP-008 décourage l'utilisation d'une barre oblique inversée comme celle-là. C'est trop fragile: s'il y a un espace entre la barre oblique inverse et la nouvelle ligne, celle-ci ne sera pas échappée et la barre oblique inverse sera imprimée.

Une approche plus polyvalente consiste à utiliser une fonction qui calcule la quantité de remplissage requise pour centrer le texte et l'applique via un spécificateur de mise en forme imbriqué. Par exemple:

def banner(s, width=69):
    stars = '*' * width
    pad = (width + len(s)) // 2
    return '{0}\n{1:>{2}}\n{0}'.format(stars, s, pad)

print(banner('hello'))
print(banner('Hello, world', width=16))

sortie

*********************************************************************
                                hello
*********************************************************************
****************
  Hello, world
****************

Comment ça marche

Cette chaîne de format est un peu dense, alors je suppose que je devrais essayer de l'expliquer. ;) Pour obtenir des informations complètes sur ce sujet, veuillez consulter Format Syntaxe des chaînes dans les documents. L'explication ci-dessous emprunte & paraphrase ces documents.

'{0}\n{1:>{2}}\n{0}'.format(stars, s, pad)

La substance incluse dans {} dans une chaîne de format s'appelle un "champ de remplacement". Le premier élément d'un champ de remplacement est le nom du champ facultatif. Cela nous permet d'identifier l'argument de .format associé à ce champ de remplacement. Il existe plusieurs variantes possibles pour les noms de champ. Cette chaîne de format utilise des noms numériques, de sorte qu'elle identifie les arguments .format par leur position. Autrement dit, 0 correspond à stars, 1 correspond à s et 2 correspond à pad

Si aucun nom de champ n'est donné, ils sont automatiquement renseignés par les chiffres 0, 1, 2, ... etc. (sauf si vous utilisez Python 2.6, où les noms de champ sont obligatoires). C'est très utile la plupart du temps, donc la plupart des chaînes de format ne s'embêtent pas à utiliser des noms de champs.

Après le nom du champ, nous pouvons donner un "spécificateur de format" ou une "spécification de format" qui décrit comment la valeur doit être présentée. Un deux-points : sépare le nom du champ de la spécification de format. Si vous ne fournissez pas de spécification de format, vous en obtenez une par défaut, ce qui est généralement suffisant. Mais ici, nous voulons un peu plus de contrôle, nous devons donc fournir une spécification de format.

Dans une spécification de formulaire, le signe > force le champ à être aligné à droite dans l'espace disponible. Après le signe d’alignement, nous pouvons fournir un numéro pour spécifier la largeur minimale du champ; le champ sera automatiquement agrandi si nécessaire. 

Par exemple, '{0:>6}'.format('test') dit de mettre l'argument 0 ('test') dans un espace large d'au moins 6 caractères, aligné à droite. Ce qui donne la chaîne ' test'.

Mais une spécification de format peut en réalité contenir un tout nouveau champ de remplacement! Cela nous permet de fournir une variable pour contrôler la largeur du champ. Donc, dans mon format, la chaîne {1:>{2}} dit de mettre arg 1 ici (s), aligné à droite dans un champ de largeur donnée par arg 2 (pad). Un seul niveau d'imbrication de champ de remplacement est autorisé, mais il est difficile d'imaginer une situation dans laquelle vous souhaiteriez réellement une imbrication plus profonde.

Donc, assembler le tout: '{0}\n{1:>{2}}\n{0}' indique à .format de construire une chaîne commençant par arg 0 (stars) en utilisant la spécification de format par défaut, suivie d'une nouvelle ligne, suivie de arg 1 (s) aligné à droite dans un champ de largeur pad, suivi de une autre nouvelle ligne, suivie de nouveau par arg 0 (stars).

J'espère que cela a eu assez de sens. :)


Dans Python 3.6+, nous pourrions utiliser une chaîne f:

def banner(s, width=69):
    stars = '*' * width
    pad = (width + len(s)) // 2
    return f'{stars}\n{s:>{pad}}\n{stars}'
7
PM 2Ring

vous pouvez procéder par exemple comme:

print('*'*80)
print('{msg:^80s}'.format(msg = 'HELLO')) #^ centers the message
print('*'*80)

ou si vous voulez avoir la dynamique text-width:

def fn(msg, w = 80):
    delim = '*'*w
    fmt = '{msg:^%ds}'%w

    print(delim)
    print(fmt.format(msg=msg))
    print(delim)

fn('hello')

ou une version légèrement généralisée si vous avez besoin d'écrire dans un fichier:

import sys

def fn(msg, w = 80, F = sys.stdout):
    delim = '*'*w
    fmt = '{delim:s}\n{msg:^%ds}\n{delim:s}\n'%w
    F.write(fmt.format(delim = delim, msg = msg))

fn('hello')
6
ewcz

Peut être :

print '*' * 80 + '\n' + ' ' * 38 + 'hello' + '\n' + '*' *80

OU S'il s'agit de python3

a = lambda x,c,mess: print(c*x + ('\n' if not mess else mess))
a(80, '*', None)
a(38, ' ', 'Hello')
a(80, '*', None)
0
rajkris

Une autre solution consisterait à utiliser le module textwrap

import textwrap

decorator = """\
            ****
            {0}
            ****"""

print(textwrap.dedent(decorator.format("hello")))
0
Ludisposed