Python 格式化包含非ascii字符的列

Python 格式化包含非ascii字符的列,python,python-2.7,unicode,string-formatting,non-ascii-characters,Python,Python 2.7,Unicode,String Formatting,Non Ascii Characters,所以我想对齐包含非ascii字符的字段。以下似乎不起作用: for word1, word2 in [['hello', 'world'], ['こんにちは', '世界']]: print "{:<20} {:<20}".format(word1, word2) hello world こんにちは 世界 对于[['hello',world',['こんにちは', '世界']]: 打印“{:您正在格式化一个多字节编码的字符串。您似乎正在

所以我想对齐包含非ascii字符的字段。以下似乎不起作用:

for word1, word2 in [['hello', 'world'], ['こんにちは', '世界']]:
    print "{:<20} {:<20}".format(word1, word2)

hello                world
こんにちは      世界
对于[['hello',world',['こんにちは', '世界']]:

打印“{:您正在格式化一个多字节编码的字符串。您似乎正在使用UTF-8对文本进行编码,并且该编码在每个代码点上使用多个字节(根据特定字符的不同,在1到4之间)。格式化字符串会计算字节,而不是代码点,这是字符串最终未对齐的原因之一:

>>> len('hello')
5
>>> len('こんにちは')
15
>>> len(u'こんにちは')
5
改为将文本格式化为Unicode字符串,以便可以计算代码点,而不是字节:

for word1, word2 in [[u'hello', u'world'], [u'こんにちは', u'世界']]:
    print u"{:<20} {:<20}".format(word1, word2)
然后在我的终端中生成所需的对齐方式:

[u'hello',u'world',[u'こんにちは', u'世界']]:
…打印u“{0:这不是一件容易的任务-这不是简单的“非ascii”-它们是宽unicode字符,并且它们的显示非常复杂-从根本上说,更多地取决于您使用的终端类型,而不是您在其中放置的空格数

首先,您必须使用UNICODE字符串。因为您使用的是Python 2,这意味着您应该在文本引号前面加上“u”

乍一看,这些长度似乎可以用来计算字符宽度。不幸的是,utf-8编码字符的字节长度与字符的实际显示宽度无关。单宽unicode字符在utf-8中也是多字节的(如
ç

现在,在我们讨论unicode之后,Python确实包含了一些实用程序—包括一个函数调用,以了解每个unicode字符的显示单位是什么—它是
unicode。east\u asian\u width
—这允许您有一种方法来计算每个字符串的宽度,然后获得适当的间距数字:

自动计算“{: 这在我的终端上对我起了作用:

hello              world
こんにちは          世界
但正如Martijn所说,它比这更复杂。有模糊的字符和终端类型。 如果您确实需要在文本终端中对齐此文本,那么您应该使用终端库,例如whcih,它允许您指定打印字符串的显示坐标。这样,您只需在打印每个单词之前将光标明确定位在相应的列上,并避免所有显示宽度计算

def calc_width(target, text):
    return target - sum(unicodedata.east_asian_width(c) in 'WF' for c in text)

for word1, word2 in [[u'hello', u'world'], [u'こんにちは', u'世界']]:
    print u"{0:<{1}} {2:<{3}}".format(word1, calc_width(20, word1), word2, calc_width(20,  word2))
>>> for word1, word2 in [[u'hello', u'world'], [u'こんにちは', u'世界']]:
...     print u"{0:<{1}} {2:<{3}}".format(word1, calc_width(20, word1), word2, calc_width(20,  word2))
...
hello                world
こんにちは           世界
for word1, word2 in [[u'hello', u'world'], [u'こんにちは', u'世界']]:
    print "{:<20} {:<20}".format(word1, word2)
>>> a = u'こんにちは'
>>> len(a)
5
>>> b = 'こんにちは'
>>> len(b)
15
import unicode

def display_len(text):
    res = 0
    for char in text:
        res += 2 if unicodedata.east_asian_width(char) == 'W' else 1
    return res

for word1, word2 in [[u'hello', u'world'], [u'こんにちは', u'世界']]:
    width_format = u"{{}}{}{{}}".format(" " * (20 - (display_len(word1))))
    print width_format.format(word1, word2)
hello              world
こんにちは          世界