【问题标题】:Python utf-8, howto align printoutPython utf-8,如何对齐打印输出
【发布时间】:2010-03-19 11:54:19
【问题描述】:

我有一个包含日语字符和“正常”字符的数组。 如何对齐这些打印输出?

#!/usr/bin/python
# coding=utf-8

a1=['する', 'します', 'trazan', 'した', 'しました']
a2=['dipsy', 'laa-laa', 'banarne', 'po', 'tinky winky']

for i,j in zip(a1,a2):
    print i.ljust(12),':',j

print '-'*8

for i,j in zip(a1,a2):
    print i,len(i)
    print j,len(j)

输出:

する       : dipsy
します    : laa-laa
trazan       : banarne
した       : po
しました : tinky winky
--------
する 6
dipsy 5
します 9
laa-laa 7
trazan 6
banarne 7
した 6
po 2
しました 12
tinky winky 11

谢谢, //弗雷德里克

【问题讨论】:

  • 我认为对日本人来说,你有“正常”和罗马字的混合体。对泰国人来说......

标签: python unicode utf-8


【解决方案1】:

使用unicodedata.east_asian_width函数,在计算字符串长度时跟踪哪些字符是窄的和宽的。

#!/usr/bin/python
# coding=utf-8

import sys
import codecs
import unicodedata

out = codecs.getwriter('utf-8')(sys.stdout)

def width(string):
    return sum(1+(unicodedata.east_asian_width(c) in "WF")
        for c in string)

a1=[u'する', u'します', u'trazan', u'した', u'しました']
a2=[u'dipsy', u'laa-laa', u'banarne', u'po', u'tinky winky']

for i,j in zip(a1,a2):
    out.write('%s %s: %s\n' % (i, ' '*(12-width(i)), j))

输出:

する          : dipsy
します        : laa-laa
trazan        : banarne
した          : po
しました      : tinky winky

在某些网络浏览器字体中看起来不正确,但在终端窗口中它们正确排列。

【讨论】:

  • tab 不是解决方案,我真正在做的是生成包含日语动词变位的狮身人面像表。我会检查east_asian_width函数...
  • 完美,至少在理论上我一直在寻找。尝试运行它虽然给了我这个: $ ./try.py Traceback (最近一次调用最后): File "./try.py", line 12, in print i,' '*(12-width( i)),':',j UnicodeEncodeError: 'latin-1' codec can't encode characters in position 0-1: ordinal not in range(256)
  • @Fredrick 哎哟,您可能需要查看sys.setdefaultencodingblog.ianbicking.org/illusive-setdefaultencoding.html
  • 非常烦人,不能让它工作... >>> import sys >>> sys.getdefaultencoding() 'utf-8' 你能发布完整的代码吗?
  • 好的,我认为正确的解决方案是不使用默认编码,而是将每个 unicode 字符串显式编码为您想要的编解码器。请参阅此问题 (stackoverflow.com/questions/492483/…)。 OS X 似乎已经解决了这个问题......
【解决方案2】:

使用 unicode 对象而不是字节字符串:

#!/usr/bin/python
# coding=utf-8

a1=[u'する', u'します', u'trazan', u'した', u'しました']
a2=[u'dipsy', u'laa-laa', u'banarne', u'po', u'tinky winky']

for i,j in zip(a1,a2):
    print i.ljust(12),':',j

print '-'*8

for i,j in zip(a1,a2):
    print i,len(i)
    print j,len(j)

Unicode 对象直接处理字符。

【讨论】:

  • using u'string' 我得到 UnicodeEncodeError: 'latin-1' codec can't encode characters in position 0-1: ordinal not in range(256) 通过打印 j.encoding( 'utf-8') 但这似乎非常尴尬......
  • @jleedev—我的控制台另有说明。你可以说得更详细点吗?你得到什么结果? @Fredrik—听起来您的终端想要使用 Latin-1 编码。您必须找到一种方法来说服它使用 UTF-8,或者将输出写入文件而不是打印(我推荐 import codecs; f = codecs.open('output.txt', encoding='utf-8'))。祝你好运!
  • @jleedev—啊。我明白发生了什么事。这在某种程度上取决于你的字体,python 对此无能为力,但它确实解决了第二个for 循环中的字符数问题。
【解决方案3】:

您需要手动构建字符串,还需要手动构建格式长度。这没有简单的方法

下面的三个函数都是这样做的(需要unicodedata):

shortenStringCJK:正确缩短到适合某些输出的长度(不是为了获取 X 字符而缩短长度)

def shortenStringCJK(string, width, placeholder='..'):
# get the length with double byte charactes
string_len_cjk = stringLenCJK(str(string))
# if double byte width is too big
if string_len_cjk > width:
    # set current length and output string
    cur_len = 0
    out_string = ''
    # loop through each character
    for char in str(string):
        # set the current length if we add the character
        cur_len += 2 if unicodedata.east_asian_width(char) in "WF" else 1
        # if the new length is smaller than the output length to shorten too add the char
        if cur_len <= (width - len(placeholder)):
            out_string += char
    # return string with new width and placeholder
    return "{}{}".format(out_string, placeholder)
else:
    return str(string)

stringLenCJK: 获取正确的长度(如在终端上占用的空间)

def stringLenCJK(string):
    # return string len including double count for double width characters
    return sum(1 + (unicodedata.east_asian_width(c) in "WF") for c in string)

formatLen:格式化长度以根据双字节字符调整宽度。没有这个长度会不平衡。

def formatLen(string, length):
    # returns length udpated for string with double byte characters
    # get string length normal, get string length including double byte characters
    # then subtract that from the original length
    return length - (stringLenCJK(string) - len(string))

然后输出一些字符串:预定义格式字符串

format_str = "|{{:<{len}}}|"
format_len = 26
string_len = 26

并输出如下(其中_string是要输出的字符串)

print("Normal : {}".format(
    format_str.format(
        len=formatLen(shortenStringCJK(_string, width=string_len), format_len))
    ).format(
        shortenStringCJK(_string, width=string_len)
    )
)

【讨论】:

  • 感谢您回答我 8 岁的问题 :-)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-08
  • 2018-05-11
  • 2016-12-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多