3

I am pulling data from the web and want to align it in a table in a terminal window. I can align the text fine in most cases but when the text contains certain symbols or foreign characters things get messy. How can I handle these characters? Here is an example with the problem on the third line of output:

>>> items = "Apple tree", "Banana plant", "Orange 으르", "Goodbye"
>>> values = 100, 200, 300, 400
>>> for i, v in zip(items, values):
...     print "%-15s : %-4s" % (i, v)
... 
Apple tree      : 100 
Banana plant    : 200 
Orange 으르   : 300 
Goodbye         : 400 
>>> 

Note: I quoted all the items correctly. The "Orange"closing quotes don't show correctly here on Stack Overflow but they display fine in the terminal window.

UPDATE: I have added a bounty to this question. I am looking for a solution that can be implemented without too much additional code and without using external libraries. It should also work with python 2.7+ and 3.x (conditionals that test for versions and apply different fixes would be fine). Also it should not require any additional system configuration or changing of fonts or changing any terminal settings of a standard Debian/Ubuntu installation.

Holy Mackerel
  • 3,259
  • 1
  • 25
  • 41
  • Out of curiosity,since I can't see the symbols (all I see are boxes in lame XP), what does `len(i)` for each say? How does the output of `i.ljust(15)` compare to string formatting? What about `'{:<15}'.format(i)`? – mhlester Feb 12 '14 at 01:18
  • Why are you using bytestrings? – Ignacio Vazquez-Abrams Feb 12 '14 at 01:23
  • I get exactly the same problem using `print i.ljust(15), v`. `map(len, items)` shows `[10, 12, 13, 7]` and also the same problem using `'{:<15}'.format(i)` – Holy Mackerel Feb 12 '14 at 01:24
  • @IgnacioVazquez-Abrams I fetch the web content as json and decode it with `str.decode("utf8")`. Then when I display it I encode the text (under python2.7) or just print them normally with python3.3. The characters display correctly in both python versions but the alignment does not. I cut and pasted the characters from that output here as an example. – Holy Mackerel Feb 12 '14 at 01:38
  • This question is a duplicate. See http://stackoverflow.com/questions/2476953/python-utf-8-howto-align-printout – jdhildeb Feb 15 '14 at 18:50

1 Answers1

4

The special behaviour for those particular characters can be identified using the East Asian width property from their Unicode data. Taking the suggestion from Programmatically tell if a Unicode character takes up more than one character space in a terminal and using that value for alignment:

#!/usr/bin/python3

import unicodedata

items = "Apple tree", "Banana plant", "Orange 으르", "Goodbye"
values = 100, 200, 300, 400
for i, v in zip(items, values):
    eawid = len(i) + sum(1 for v in i if unicodedata.east_asian_width(v) == 'W')
    pad = ' ' * (15 - eawid)
    print("%s%s : %-4s" % (i, pad, v))

gives:

Apple tree      : 100 
Banana plant    : 200 
Orange 으르     : 300 
Goodbye         : 400 

This may appear misaligned if your browser is using a 1.5-width glyph for those characters; in my terminal, plan is exactly the same width as 으르.

Syntax here is Python 3, but the same technique works in 2.7.

Community
  • 1
  • 1
Joe
  • 29,416
  • 12
  • 68
  • 88