188

I am processing a text file containing coordinates x, y, z

     1      128  1298039
123388        0        2
....

every line is delimited into 3 items using

words = line.split()

After processing data I need to write coordinates back in another txt file so as items in each column are aligned right (as well as the input file). Every line is composed of the coordinates

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

Is there any manipulator like std::setw() etc. in C++ allowing to set the width and alignment?

codeforester
  • 34,080
  • 14
  • 96
  • 122
justik
  • 3,841
  • 6
  • 29
  • 51

8 Answers8

284

Try this approach using the newer str.format syntax:

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

And here's how to do it using the old % syntax (useful for older versions of Python that don't support str.format):

line_new = '%12s  %12s  %12s' % (word[0], word[1], word[2])
Michael Mior
  • 27,152
  • 8
  • 85
  • 111
Mark Byers
  • 767,688
  • 176
  • 1,542
  • 1,434
  • 51
    Note how the "old" syntax is cleaner, easier to read, and shorter. – fyngyrz Dec 13 '15 at 18:01
  • 3
    I thought I'd add a more direct link than the one provided: https://docs.python.org/2/library/string.html#format-specification-mini-language – brw59 May 12 '16 at 07:12
  • 61
    Shorter for sure, I don't know what cleaner really means, but 'easier to read' is just because it's familiar, I think. If you're not already familiar with one of them, the new format seems easier to read. ".format" for string formatting certainly seems more intuitive than percentage/modulo. Right arrow for right alignment seems pretty intuitive too. – Mark May 28 '17 at 10:54
  • 1
    If you are using python 2 and alligning lines with non-latin symbols use unicode! (`u'...'.format`) – yanpas Jun 01 '17 at 15:55
  • How can I combine both > < in python 2 with the same string using % – Khalil Al Hooti Dec 25 '18 at 19:10
  • 3
    @Mark One way the old way is cleaner is that it uses fewer characters. Yes with familiarity the new way becomes intuitive but it is not cleaner and simpler. The old way is more intuitive for those who are accustomed to the syntax that comes to us through the venerable C language, a language of exemplary conciseness and precision. What precedent is there for the new way? – Stephen Boston Jan 26 '19 at 23:25
  • @StephenBoston So you're saying that there is a way that we could make Python just as readable as C? That must be a popular cause indeed. – Mark Jan 27 '19 at 11:12
  • @Mark Ha! Good point. Gave me a laugh. But if I may piggyback on your point about familiarity, experienced C programmers find C easier to read than, say, Perl at first glance, so... After that though I prefer the old way even when I can read the new way. I find the new way cryptic and verbose, prefer the new format function. – Stephen Boston Jan 27 '19 at 12:49
  • 3
    @StephenBoston I'll leave readability to the experts, but the new way is absolutely cleaner. Parens are no longer optional. % can be confused with a math operator (albeit, not likely in context, but at a glance sure). The old way would fail if word[n] is not of the expected type (string in this case). The new way doesn't need to know what the incoming type is, it always works. Clean and simple. To be fair, I never got comfortable with the printf style (I mostly did C with cout). – Zim Oct 04 '19 at 18:00
  • @Zim @StephenBoston The new way offers another advantage. You are no longer tied to argument positions. You can use something like `"{key:>12s} - {val:<12s}".format(key="TisAKey", val="AndIt'sValue")` so for very large string templates (say if you're generating whole text files / code files, whatever) you can use a dictionary: `BIG_FMT_STRING.format(**fmt_key_dict)`. It's been handy for some code I am writing to generate a "build system" for a Vivado HDL project from a few descriptor JSON files and a quick scan of the VHDL and XDC files. – James Matta Jan 18 '22 at 17:56
67

You can align it like that:

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

where > means "align to right" and 8 is the width for specific value.

And here is a proof:

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


       1      128  1298039
  123388        0        2

Ps. *line means the line list will be unpacked, so .format(*line) works similarly to .format(line[0], line[1], line[2]) (assuming line is a list with only three elements).

Tadeck
  • 125,377
  • 26
  • 148
  • 197
63

It can be achieved by using rjust:

line_new = word[0].rjust(10) + word[1].rjust(10) + word[2].rjust(10)
clwen
  • 18,566
  • 30
  • 73
  • 92
46

Here is another way how you can format using 'f-string' format:

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}",
)

This will provide the following output:

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

What you are doing here is you are saying that the first column is 15 chars long and it's left-justified and the second column (values) is 10 chars long and it's right-justified.

If you joining items from the list and you want to format space between items you can use `` and regular formatting techniques.

This example separates each number by 3 spaces. The key here is f"{'':>3}"

print(f"{'':>3}".join(str(i) for i in range(1, 11)))

output:

1   2   3   4   5   6   7   8   9   10
Vlad Bezden
  • 72,691
  • 22
  • 233
  • 168
  • 1
    Is there a way to parametrise the width of the formats? In this example if you decide to change the formatting to 20 and 15 widths it requires to change multiple lines. `widths = [15, 10]` `f"{'Trades:':width[1]}",` I'd like to achieve sth like above. – Tomasz Sabała Oct 02 '19 at 10:28
  • 4
    Got it! Maybe someone will find it helpful. I need one more nested brackets for this so: `f"{'Trades:':{width[1]}}"` – Tomasz Sabała Oct 02 '19 at 10:35
  • 1
    Sometimes the best answers are the ones that don't answer the exact question. Thanks for this! :) – Brian Wiley Mar 26 '20 at 03:05
  • @BrianWiley Exactly! I too was looking to format string literals. I always forget the "string-in-string" hack (i.e. using ` ' ' ` inside ` " " `). – pfabri Feb 11 '21 at 14:45
35

I really enjoy a new literal string interpolation in Python 3.6+:

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

Reference: PEP 498 -- Literal String Interpolation

dmitry_romanov
  • 4,760
  • 1
  • 30
  • 35
6

Simple tabulation of the output:

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

output:

variable a    variable b
      0.33         66.67

%10.2f: 10 is the minimum length and 2 is the number of decimal places.

Tunaki
  • 125,519
  • 44
  • 317
  • 399
Thoran
  • 7,988
  • 7
  • 38
  • 48
5

To do it by using f-string and with control of the number of trailing digits:

print(f'A number -> {my_number:>20.5f}')
Learning is a mess
  • 5,905
  • 5
  • 30
  • 64
0

Mixing Vlad's fine content with others, the code can also be written for readabily and ease-of-use like ...

>>> cnt = wins = losses      = str(   2)
>>> evens = win_r = mean_w   = str(  14)
>>> mean_l = mean_trd = sd   = str( 336)
>>> max_l = max_w = sharpe_r = str(4278)
>>>
>>> rpad = 10
>>>
>>> print(
...     '\n Trades         ' +      cnt.rjust(rpad),
...     '\n Wins           ' +     wins.rjust(rpad),
...     '\n Losses         ' +   losses.rjust(rpad),
...     '\n Breakeven      ' +    evens.rjust(rpad),
...     '\n Win/Loss Ratio ' +    win_r.rjust(rpad),
...     '\n Mean Win       ' +   mean_w.rjust(rpad),
...     '\n Mean Loss      ' +   mean_l.rjust(rpad),
...     '\n Mean           ' + mean_trd.rjust(rpad),
...     '\n Std Dev        ' +       sd.rjust(rpad),
...     '\n Max Loss       ' +    max_l.rjust(rpad),
...     '\n Max Win        ' +    max_w.rjust(rpad),
...     '\n Sharpe Ratio   ' + sharpe_r.rjust(rpad),
... )

 Trades                  2
 Wins                    2
 Losses                  2
 Breakeven              14
 Win/Loss Ratio         14
 Mean Win               14
 Mean Loss             336
 Mean                  336
 Std Dev               336
 Max Loss             4278
 Max Win              4278
 Sharpe Ratio         4278
gseattle
  • 912
  • 1
  • 12
  • 23