使用多字节的UTF-8字符进行Python str.format格式化操作

4

我试图在Python中打印日语字符,并使其对齐成列。似乎日语字符的宽度相当于两个空格,因此对齐无法正常工作。

以下是代码:

def print_kanji(s, k):
    print('{:<20}{:<10}{:<10}{:<10}'
        .format(s, k['reading'][0], k['reading'][1], k['kanji']))

# Being 's' some input string and 'k' a map which contains readings in the 3 different japanese alphabets.

我得到的输出如下:
decir               いう        イウ        言う        

pequeño             すくない      スクナイ      少ない       

niño                こども       コドモ       子供        

ya [ha hecho X]     もう        モウ

左侧列是西班牙语,但这不重要。重要的是右侧的3列没有对齐。我已经计算了位置数,它是正确的,也就是说,第一列日文始终为10个“位置”长,问题在于日文字形是2个位置宽,而空格只有1个位置。 我也已经检查过,使用日语输入法时,一个空格也是两个位置宽,因此我应该能够通过将“拉丁”空格(1个位置宽)替换为日文空格来解决问题。
如何更改format将用于对齐字符串的字符?
编辑
我发现str.format有一个名为fill的参数。我尝试用日文空格(两个位置宽)替换它,结果更糟糕了。
编辑2
我通过实现这个函数解决了它。
def get_formatted_kanji(h, k, kn):
    h2 = h + str(' ' * (10 - 2*len(h)))
    k2 = k + str(' ' * (10 - 2*len(h)))
    kn2 = kn + str(' ' * (10 - 2*len(h)))
    return h2 + k2 + kn2

# being h, k and kn the three 'japanese strings' to be formatted in columns

然而,有没有更好的(内置的)方法来实现这个?
2个回答

6

在终端中,某些字符会占用两个列宽度,而其他字符则只占用一个列宽度。您可以使用Python的unicodedata模块来确定每个字符的占用宽度,该模块具有一个east_asian_width()函数。

以下是如何使用它来填充您的文本的示例:

import unicodedata
table = [
    ('decir', 'いう', 'イウ', '言う'), 
    ('pequeño', 'すくない', 'スクナイ', '少ない'), 
    ('niño', 'こども', 'コドモ', '子供'), 
    ('ya [ha hecho X]', 'もう', 'モウ', ''),
]

WIDTHS = {
    'F': 2,
    'H': 1,
    'W': 2,
    'N': 1,
    'A': 1, # Not really correct...
    'Na': 1,
}

def pad(text, width):
    text_width = 0
    for ch in text:
        width_class = unicodedata.east_asian_width(ch)
        text_width += WIDTHS[width_class]
    if width <= text_width:
        return text
    return text + ' ' * (width - text_width)

for s, reading1, reading2, kanji in table:
    print('{}{}{}{}'.format(
        pad(s, 20),
        pad(reading1, 10),
        pad(reading2, 10),
        pad(kanji, 10),
    ))

这是在我的系统上(macOS)的屏幕截图: The same table, with columns lined up visually. 限制:
上述代码无法处理Unicode组合字符。更完整的实现将执行Unicode文本分割,然后确定每个字形簇的宽度。我相信有库可以为您完成此操作。
语言说明:
作为说明,我不认为“少ない”和“pequeño”这些词是相对应的。西班牙语单词“pequeño”指的是某物的大小,“少ない”则指数量不足。
我认为更可能的是:
- poco: 少ない - pequeño: 小さい

只有东亚字符是双宽的吗?还是其他字符也是双宽的? - Mark Ransom
1
@MarkRansom:字符'A'(即U+FF21)是双倍宽度,它是一个拉丁字符。 - Dietrich Epp
@MarkRansom 我认为其他字符只是“半角和全角字符”Unicode块中包含的内容。请参阅https://en.wikipedia.org/wiki/Halfwidth_and_Fullwidth_Forms_(Unicode_block)。(但有些令人困惑的是,该块还包括一组“正常”宽度字符:日文片假名的“半”宽度版本。) - sideshowbarker

0

您应该能够通过以下方式更改语言格式:

>>> import locale
>>> locale.setlocale(locale.LC_ALL, 'ja-JP') # or 'jpn'

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接