Formatar sequência de saída, alinhamento à direita

149

Estou processando um arquivo de texto contendo as coordenadas x, y, z

     1      128  1298039
123388        0        2
....

cada linha é delimitada em 3 itens usando

words = line.split()

Após o processamento dos dados, preciso gravar as coordenadas novamente em outro arquivo txt, para que os itens em cada coluna sejam alinhados à direita (assim como o arquivo de entrada). Cada linha é composta pelas coordenadas

line_new = words[0]  + '  ' + words[1]  + '  ' words[2].

Existe algum manipulador como o std::setw()C ++ que permita definir a largura e o alinhamento?

justik
fonte

Respostas:

230

Tente esta abordagem usando a str.formatsintaxe mais recente :

line_new = '{:>12}  {:>12}  {:>12}'.format(word[0], word[1], word[2])

E aqui está como fazer isso usando a %sintaxe antiga (útil para versões mais antigas do Python que não suportam str.format):

line_new = '%12s  %12s  %12s' % (word[0], word[1], word[2])
Mark Byers
fonte
39
Observe como a sintaxe "antiga" é mais limpa, mais fácil de ler e mais curta.
Fyngyrz
2
Pensei em adicionar uma ligação mais directa do que o previsto: docs.python.org/2/library/...
brw59
48
Mais curto, com certeza, não sei o que realmente significa limpador, mas 'mais fácil de ler' é apenas porque é familiar, eu acho. Se você ainda não conhece um deles, o novo formato parece mais fácil de ler. ".format" para formatação de strings certamente parece mais intuitivo que porcentagem / módulo. A seta para a direita para o alinhamento à direita também parece bastante intuitiva.
Mark
2
@ Mark Uma maneira que a maneira antiga é mais limpa é usar menos caracteres. Sim, com a familiaridade, a nova maneira se torna intuitiva, mas não é mais limpa e simples. O modo antigo é mais intuitivo para aqueles que estão acostumados com a sintaxe que nos chega através da venerável linguagem C, uma linguagem de concisão e precisão exemplares. Que precedente existe para o novo caminho?
Stephen Boston
2
@StephenBoston Vou deixar a legibilidade para os especialistas, mas a nova maneira é absolutamente mais limpa. Parens não é mais opcional. % pode ser confundido com um operador de matemática (embora não seja provável no contexto, mas de relance, com certeza). A maneira antiga falharia se a palavra [n] não fosse do tipo esperado (neste caso, string). A nova maneira não precisa saber qual é o tipo de entrada, sempre funciona. Limpo e simples. Para ser justo, nunca me senti à vontade com o estilo printf (geralmente fiz C com cout).
Zim
53

Isso pode ser alcançado usando rjust:

line_new = word[0].rjust(10) + word[1].rjust(10) + word[2].rjust(10)
clwen
fonte
51

Você pode alinhá-lo assim:

print('{:>8} {:>8} {:>8}'.format(*words))

onde >significa " alinhar à direita " e 8é a largura do valor específico.

E aqui está uma prova:

>>> for line in [[1, 128, 1298039], [123388, 0, 2]]:
    print('{:>8} {:>8} {:>8}'.format(*line))


       1      128  1298039
  123388        0        2

Ps. *linesignifica que a linelista será descompactada, portanto, .format(*line)funciona de maneira semelhante a .format(line[0], line[1], line[2])(supondo que lineseja uma lista com apenas três elementos).

Tadeck
fonte
27

Eu realmente gosto de uma nova interpolação de string literal no Python 3.6+:

line_new = f'{word[0]:>12}  {word[1]:>12}  {word[2]:>12}'

Referência: PEP 498 - Interpolação de cordas literais

dmitry_romanov
fonte
18

Aqui está outra maneira de como você pode formatar usando o formato 'f-string':

print(
    f"{'Trades:':<15}{cnt:>10}",
    f"\n{'Wins:':<15}{wins:>10}",
    f"\n{'Losses:':<15}{losses:>10}",
    f"\n{'Breakeven:':<15}{evens:>10}",
    f"\n{'Win/Loss Ratio:':<15}{win_r:>10}",
    f"\n{'Mean Win:':<15}{mean_w:>10}",
    f"\n{'Mean Loss:':<15}{mean_l:>10}",
    f"\n{'Mean:':<15}{mean_trd:>10}",
    f"\n{'Std Dev:':<15}{sd:>10}",
    f"\n{'Max Loss:':<15}{max_l:>10}",
    f"\n{'Max Win:':<15}{max_w:>10}",
    f"\n{'Sharpe Ratio:':<15}{sharpe_r:>10}",
)

Isso fornecerá a seguinte saída:

Trades:              2304
Wins:                1232
Losses:              1035
Breakeven:             37
Win/Loss Ratio:      1.19
Mean Win:           0.381
Mean Loss:         -0.395
Mean:               0.026
Std Dev:             0.56
Max Loss:          -3.406
Max Win:             4.09
Sharpe Ratio:      0.7395

O que você está fazendo aqui é que está dizendo que a primeira coluna tem 15 caracteres e é justificada à esquerda e a segunda coluna (valores) tem 10 caracteres e é justificada à direita.

Vlad Bezden
fonte
Existe uma maneira de parametrizar a largura dos formatos? Neste exemplo, se você decidir alterar a formatação para 20 e 15 larguras, será necessário alterar várias linhas. widths = [15, 10] f"{'Trades:':<width[0]}{cnt:>width[1]}",Eu gostaria de alcançar sth como acima.
Tomasz Sabała 2/10/19
1
Entendi! Talvez alguém ache útil. Eu preciso de mais um colchete aninhado para isso:f"{'Trades:':<{width[0]}}{cnt:>{width[1]}}"
Tomasz Sabała 02/10/19
1
Às vezes, as melhores respostas são aquelas que não respondem à pergunta exata. Obrigado por isso! :)
Brian Wiley
5

Tabulação simples da saída:

a = 0.3333333
b = 200/3
print("variable a    variable b")
print("%10.2f    %10.2f" % (a, b))

resultado:

variable a    variable b
      0.33         66.67

% 10.2f: 10 é o comprimento mínimo e 2 é o número de casas decimais.

Thoran
fonte
1

Para fazer isso usando a string f e com o controle do número de dígitos à direita:

print(f'A number -> {my_number:>20.5f}')
Aprender é uma bagunça
fonte