我正在打印格式化的表格。但是有时这些用户生成的字符占用多个字符宽度,并且弄乱了格式,如下面的屏幕截图所示...
“标题”列的宽度格式为68个字节。但是这些“特殊字符”占用的宽度超过1个字符,但仅计为1个字符。这会将列推到边界之外。
print('{0:16s}{3:<18s}{1:68s}{2:>8n}'.format((
' ' + streamer['user_name'][:12] + '..') if len(streamer['user_name']) > 12 else ' ' + streamer['user_name'],
(streamer['title'].strip()[:62] + '..') if len(streamer['title']) > 62 else streamer['title'].strip(),
streamer['viewer_count'],
(gamesDic[streamer['game_id']][:15] + '..') if len(gamesDic[streamer['game_id']]) > 15 else gamesDic[streamer['game_id']]))
关于如何处理这些特殊字符的任何建议?
编辑:我将有问题的字符串打印到文件中。
()L LIVE SUBS GET SNAPCHAT
edit2
为什么这些字符不能在字符边界上对齐?
edit3:
今天,前两个字符产生了奇怪的输出。但是在下面的每种情况下,列都是对齐的。
第一个孤立的字符...
title[0]
孤立的第二个字符... title[1]
第一个和第二个字符在一起。.title[0] + title[1]
答案 0 :(得分:2)
我已经基于@snakecharmerb的comment编写了自定义字符串格式化程序,但仍然存在“半字符宽度”问题:
import unicodedata
def fstring(string, max_length, align='l'):
string = str(string)
extra_length = 0
for char in string:
if unicodedata.east_asian_width(char) == 'F':
extra_length += 1
diff = max_length - len(string) - extra_length
if diff > 0:
return string + diff * ' ' if align == 'l' else diff * ' ' + string
elif diff < 0:
return string[:max_length-3] + '.. '
return string
data = [{'user_name': 'shroud', 'game_id': 'Apex Legends', 'title': 'pathfinder twitch prime loot YAYA @shroud on socials for update', 'viewer_count': 66200},
{'user_name': 'Amouranth', 'game_id': 'ASMR', 'title': ' ( ) ✨ LIVE SUBS GET SNAPCHAT', 'viewer_count': 2261}]
for d in data:
name = fstring(d['user_name'], 20)
game_id = fstring(d['game_id'], 15)
title = fstring(d['title'], 62)
count = fstring(d['viewer_count'], 10, align='r')
print('{}{}{}{}'.format(name, game_id, title, count))
它产生输出:
(由于格式会丢失,因此无法将其发布为文本)
答案 1 :(得分:2)
我对这个问题发表了评论:
“ LIVE”中的字符是Fullwidth个字符。一种骇人听闻的方式 处理它们可能是用
unicodedata.east_asian_width(char)
(全角返回“ F” 字符)并替换为的最终字符unicodedata.name(char)
(或仅将其视为长度2)
此“答案”实质上是另一条评论,但对于评论字段而言太长了。
按照Alderven的answer的实现,此hack几乎适用于OP,但是示例字符串呈现为额外的一半字符宽度(请注意,示例字符串不包含任何东亚半角字符。)
使用以下测试语句,我无法重现此确切的行为,其中s
是问题的示例字符串,更改了删除的字符:
print((s + (68 - (len(s) + sum(1 for x in s if ud.east_asian_width(x) in ('F', 'N', 'W')))) * 'x')+ '\n'+ ('x' * 68))
在Debian上的Gnome终端中的Python 3.6解释器中,使用默认的等宽常规字体,删除全角字符会导致示例字符串的显示时间明显长于三个字符。 等效的字符串“ x”。
删除全角和宽(东亚宽度“ W”)字符会产生一个字符串,该字符串看起来具有与等价的“ x”相同的长度。
在OpenSuse上的Python 3.7 KDE Konsole终端中,使用Ubuntu Monospace常规字体,无论我将全角,宽或中性(“ N”)字符组合在一起,都无法生成呈现相同长度的字符串删除。
我确实注意到,在单独使用Konsole进行渲染时,火花字符(✨)似乎占据了额外的一半宽度,但是在测试整个字符串时看不到任何一半的宽度差异。
我怀疑问题在于Python无法控制的低级渲染,因为Unicode standard上的注释说明:
注意:East_Asian_Width属性不适用于现代人 终端仿真器,没有根据具体情况进行适当调整 基础。此类终端仿真器需要一种方法来解决 在这种环境下,必须使用半角/全角二分法, 但是East_Asian_Width属性没有提供现成的 适用于所有情况的解决方案。 Unicode的曲目越来越多 标准早已超越了东亚传统人物的界限 编码和终端仿真通常需要自定义为 支持极端情况和印刷行为的变化 时间。