如何从 len()、str.format() 和零宽度 space 获得合理的结果?
How can I get sensible results from len(), str.format() and a zero-width space?
我正在尝试将文本格式化为 table 并将结果写入文件,但我在对齐方面遇到问题,因为我的源代码有时包含 Unicode 字符 'ZERO WIDTH SPACE'或 python 中的 \u200b
。
考虑以下代码示例:
str_list = ("a\u200b\u200b", "b", "longest entry\u200b")
format_str = "|{string:<{width}}| output of len(): {length}\n"
max_width = 0
for item in str_list:
if len(item) > max_width:
max_width = len(item)
with open("tmp", mode='w', encoding="utf-8") as file:
for item in str_list:
file.write(format_str.format(string=item,
width=max_width,
length=len(item)))
上面脚本 运行 之后 'tmp' 的内容:
|a | output of len(): 3
|b | output of len(): 1
|longest entry| output of len(): 14
所以这看起来 len()
不会导致字符串的 'printed width',并且 str.format()
不知道如何处理零宽度字符。
或者,这种行为是故意的,我需要做其他事情。
明确地说,我正在寻找一种方法来获得类似这样的结果:
|a | output of len(): 1
|b | output of len(): 1
|longest entry| output of len(): 13
如果可以在不破坏我的源代码的情况下进行,我更愿意。
wcwidth 包有一个函数 wcswidth()
其中 returns 字符单元格中字符串的宽度:
from wcwidth import wcswidth
length = len('sneaky\u200bPete') # 11
width = wcswidth('sneaky\u200bPete') # 10
wcswidth(s)
和 len(s)
之间的差异可以用来纠正 str.format()
引入的错误。修改上面的代码:
from wcwidth import wcswidth
str_list = ("a\u200b\u200b", "b", "longest entry\u200b")
format_str = "|{s:<{fmt_width}}| width: {width}, error: {fmt_error}\n"
max_width = max(wcswidth(s) for s in str_list)
with open("tmp", mode='w', encoding="utf-8") as file:
for s in str_list:
width = wcswidth(s)
fmt_error = len(s) - width
fmt_width = max_width + fmt_error
file.write(format_str.format(s=s,
fmt_width=fmt_width,
width=width,
fmt_error=fmt_error))
… 产生这个输出:
|a | width: 1, error: 2
|b | width: 1, error: 0
|longest entry| width: 13, error: 1
它还可以为包含双角字符的字符串生成正确的输出:
str_list = ("a\u200b\u200b", "b", "㓵", "longest entry\u200b")
|a | width: 1, error: 2
|b | width: 1, error: 0
|㓵 | width: 2, error: -1
|longest entry| width: 13, error: 1
我正在尝试将文本格式化为 table 并将结果写入文件,但我在对齐方面遇到问题,因为我的源代码有时包含 Unicode 字符 'ZERO WIDTH SPACE'或 python 中的 \u200b
。
考虑以下代码示例:
str_list = ("a\u200b\u200b", "b", "longest entry\u200b")
format_str = "|{string:<{width}}| output of len(): {length}\n"
max_width = 0
for item in str_list:
if len(item) > max_width:
max_width = len(item)
with open("tmp", mode='w', encoding="utf-8") as file:
for item in str_list:
file.write(format_str.format(string=item,
width=max_width,
length=len(item)))
上面脚本 运行 之后 'tmp' 的内容:
|a | output of len(): 3
|b | output of len(): 1
|longest entry| output of len(): 14
所以这看起来 len()
不会导致字符串的 'printed width',并且 str.format()
不知道如何处理零宽度字符。
或者,这种行为是故意的,我需要做其他事情。
明确地说,我正在寻找一种方法来获得类似这样的结果:
|a | output of len(): 1
|b | output of len(): 1
|longest entry| output of len(): 13
如果可以在不破坏我的源代码的情况下进行,我更愿意。
wcwidth 包有一个函数 wcswidth()
其中 returns 字符单元格中字符串的宽度:
from wcwidth import wcswidth
length = len('sneaky\u200bPete') # 11
width = wcswidth('sneaky\u200bPete') # 10
wcswidth(s)
和 len(s)
之间的差异可以用来纠正 str.format()
引入的错误。修改上面的代码:
from wcwidth import wcswidth
str_list = ("a\u200b\u200b", "b", "longest entry\u200b")
format_str = "|{s:<{fmt_width}}| width: {width}, error: {fmt_error}\n"
max_width = max(wcswidth(s) for s in str_list)
with open("tmp", mode='w', encoding="utf-8") as file:
for s in str_list:
width = wcswidth(s)
fmt_error = len(s) - width
fmt_width = max_width + fmt_error
file.write(format_str.format(s=s,
fmt_width=fmt_width,
width=width,
fmt_error=fmt_error))
… 产生这个输出:
|a | width: 1, error: 2
|b | width: 1, error: 0
|longest entry| width: 13, error: 1
它还可以为包含双角字符的字符串生成正确的输出:
str_list = ("a\u200b\u200b", "b", "㓵", "longest entry\u200b")
|a | width: 1, error: 2
|b | width: 1, error: 0
|㓵 | width: 2, error: -1
|longest entry| width: 13, error: 1