如图红线所示,为什么打印的结果没有上下对齐,代码逻辑哪里不对吗
def query_uid_gid_ugo():
results = [['/thdfq_khsfb/pnc', '600>>600>>550', 'uid/gid/ugo校验结果正常!', 'PASSED'],
['/thdfq_khsfb/map', '600>>600>>550', 'uid/gid/ugo校验结果正常!', 'PASSED'],
['/thdfq_khsfb/percp', '600>>600>>550', 'uid/gid/ugo校验结果正常!', 'PASSED'],
['/thdfq_khsfb/model', '600>>600>>550', 'uid/gid/ugo校验结果正常!', 'PASSED'],
['/thdfq_khsfb/kznameq_bjzdkmmty', '600>>600>>550', 'uid/gid/ugo校验结果正常!', 'PASSED'],
['/thdfq_plt/hjadernk_service', '600>>600>>550', 'uid/gid/ugo校验结果正常!', 'PASSED'],
['/thdfq_plt/hjadernk', '600>>600>>555', 'uid/gid/ugo校验结果正常!', 'PASSED'],
['/thdfq_plt/thdfqos', '600>>600>>550', 'uid/gid/ugo校验结果正常!', 'PASSED'],
['/svp', '200>>200>>550', 'uid/gid/ugo校验结果正常!', 'PASSED'],
['/thdfq_hdmap', '600>>600>>770', 'uid/gid/ugo校验结果正常!', 'PASSED'],
['/thdfq_map/nzpmap', '600>>600>>770', 'uid/gid/ugo校验结果正常!', 'PASSED'],
['/thdfq_map/parkingmap', '600>>600>>777', 'uid/gid/ugo校验结果正常!', 'PASSED'],
['/thdfq_para/bjzdkmmty', '700>>201>>770', 'uid/gid/ugo校验结果正常!', 'PASSED'],
['/thdfq_para/swk', '700>>201>>775', 'uid/gid/ugo校验结果正常!', 'PASSED'],
['/thdfq_knvr/ota_cache', '200>>200>>775', 'uid/gid校验结果异常!预期值为700、201', 'FAILED'],
['/thdfq_knvr/logs', '600>>600>>777', 'uid/gid/ugo校验结果正常!', 'PASSED'],
['/thdfq_knvr/mja', '600>>600>>770', 'uid/gid/ugo校验结果正常!', 'PASSED'],
['/thdfq_knvr/eqz', '600>>600>>770', 'uid/gid/ugo校验结果正常!', 'PASSED'],
['/dsv_knvr', '200>>200>>770', 'uid/gid/ugo校验结果正常!', 'PASSED'],
['/thdfq_rawknvr', '600>>600>>770', 'uid/gid/ugo校验结果正常!', 'PASSED']]
return results
def formatted_print():
headers = ["Skds/Public", "UID/GID/UGO", "DetailsInfo", "CheckResult"]
data = query_uid_gid_ugo()
column_widths = [max(len(str(row[i])) for row in data) for i in range(len(headers))]
print(column_widths)
header_line = "\t|\t".join(f"{headers[i]:<{column_widths[i]}}" for i in range(len(headers)))
print(header_line)
for row in data:
row_line = "\t|\t".join(f"{str(item):<{column_widths[i]}}" for i, item in enumerate(row))
print(row_line)
formatted_print()
出现其他情况格式更加错误
问题点: 为什么打印的结果没有上下对齐.
分析思路:
打印的问题从两方面着手:
1.python3, print函数默认输出的编码为utf-8,但是在Python 3中,所有字符串默认都是Unicode编码,
因此编码的不同,会导致统计的长度无效.(Unicode编码下的字符串长度对utf-8的编码有意义么?不含中文的情况下时,没问题)
可以使用以下指令确认打印的输出编码
import sys
print(sys.stdout.encoding)
比较含中文和不含中文的差异
a = 'uid/gid/ugo校验结果正常!'
print(len(a)) # 18
print(len(a.encode('unicode_escape').decode())) # 53
b = "DetailsInfo"
print(len(b)) # 11
print(len(b.encode('unicode_escape').decode())) # 11
2.全角和半角的影响
c = 'uid/gid校验结果异常!预期值为700、201'
print(len(c)) # 25
print(len(c.encode('unicode_escape').decode())) # 85
解决办法:
将全部数据从全角转成半角, 并且转成Unicode编码.这时数据就变得一致了.
缺点:虽然对齐了,中文在Unicode编码下是乱码.
import unicodedata
def query_uid_gid_ugo():
results = [['/thdfq_khsfb/pnc', '600>>600>>550', 'uid/gid/ugo校验结果正常!', 'PASSED'],
['/thdfq_khsfb/map', '600>>600>>550', 'uid/gid/ugo校验结果正常!', 'PASSED'],
['/thdfq_khsfb/percp', '600>>600>>550', 'uid/gid/ugo校验结果正常!', 'PASSED'],
['/thdfq_khsfb/model', '600>>600>>550', 'uid/gid/ugo校验结果正常!', 'PASSED'],
['/thdfq_khsfb/kznameq_bjzdkmmty', '600>>600>>550', 'uid/gid/ugo校验结果正常!', 'PASSED'],
['/thdfq_plt/hjadernk_service', '600>>600>>550', 'uid/gid/ugo校验结果正常!', 'PASSED'],
['/thdfq_plt/hjadernk', '600>>600>>555', 'uid/gid/ugo校验结果正常!', 'PASSED'],
['/thdfq_plt/thdfqos', '600>>600>>550', 'uid/gid/ugo校验结果正常!', 'PASSED'],
['/svp', '200>>200>>550', 'uid/gid/ugo校验结果正常!', 'PASSED'],
['/thdfq_hdmap', '600>>600>>770', 'uid/gid/ugo校验结果正常!', 'PASSED'],
['/thdfq_map/nzpmap', '600>>600>>770', 'uid/gid/ugo校验结果正常!', 'PASSED'],
['/thdfq_map/parkingmap', '600>>600>>777', 'uid/gid/ugo校验结果正常!', 'PASSED'],
['/thdfq_para/bjzdkmmty', '700>>201>>770', 'uid/gid/ugo校验结果正常!', 'PASSED'],
['/thdfq_para/swk', '700>>201>>775', 'uid/gid/ugo校验结果正常!', 'PASSED'],
['/thdfq_knvr/ota_cache', '200>>200>>775', 'uid/gid校验结果异常!预期值为700、201', 'FAILED'],
['/thdfq_knvr/logs', '600>>600>>777', 'uid/gid/ugo校验结果正常!', 'PASSED'],
['/thdfq_knvr/mja', '600>>600>>770', 'uid/gid/ugo校验结果正常!', 'PASSED'],
['/thdfq_knvr/eqz', '600>>600>>770', 'uid/gid/ugo校验结果正常!', 'PASSED'],
['/dsv_knvr', '200>>200>>770', 'uid/gid/ugo校验结果正常!', 'PASSED'],
['/thdfq_rawknvr', '600>>600>>770', 'uid/gid/ugo校验结果正常!', 'PASSED']]
return results
# 全角转半角
def full_to_half(text):
return unicodedata.normalize('NFKC', text)
def get_max_length(data, _column_widths):
"""
params: data list
"""
# _column_widths = [0, 0, 0, 0]
data_list = []
for _index, _text in enumerate(data):
_text_new = full_to_half(_text)
data_list.append(_text_new)
# encode('unicode_escape') 将字符串转换为 Unicode 编码,decode() 将编码转换为字符串,
# 并用 len() 函数计算长度。注意要减去 string.count("\\u"),以排除转义字符对长度的影响。
text_width = len(_text_new.encode('unicode_escape').decode()) # - _text_new.count("\\u")
if text_width > _column_widths[_index]:
_column_widths[_index] = text_width
return data_list
def formatted_print():
headers = ["Skds/Public", "UID/GID/UGO", "DetailsInfo", "CheckResult"]
data = query_uid_gid_ugo()
data.insert(0, headers)
column_widths = [0, 0, 0, 0]
# column_widths = [max(len(str(row[i])) for row in data) for i in range(len(headers))]
data_new_list = []
for _index, row in enumerate(data):
_row = get_max_length(row, column_widths)
data_new_list.append(_row)
for _index, row_new in enumerate(data_new_list):
row_line = "\t|\t".join(f"{item.encode('unicode_escape').decode():{(column_widths[i])}}" for i, item in enumerate(row_new))
print(row_line)
print(column_widths)
# header_line = "\t|\t".join(f"{headers[i]:<{column_widths[i]}}" for i in range(len(headers)))
# print(header_line)
import sys
print(sys.stdout.encoding)
formatted_print()
这个问题是个头疼的问题,如果全是西文字符,可以完全用python的字符串格式化对齐,
问题出在西文字符与中文字符混合的情况,如果要完全对齐,一般将西文转成全角显示,如果只有固定部分是汉字,比如题中只有第3列有中文,可以只转换第三列为全角,如果字符串中只有后半部是全角,则可以通过补全全角空格来格式化,
下面给出全部转成全角的程序以供参考,虽然字体显示不大好看,但总算对齐了。
def half_all(string):
l = ''
for i in string:
s = ord(i)
if i == ' ':
l += ' '
elif 255 > s >0:
s = s + 0xfee0
l += chr(s)
else:
l += i
return l
def query_uid_gid_ugo():
results = [['/thdfq_khsfb/pnc', '600>>600>>550', 'uid/gid/ugo校验结果正常!', 'PASSED'],
['/thdfq_khsfb/map', '600>>600>>550', 'uid/gid/ugo校验结果正常!', 'PASSED'],
['/thdfq_khsfb/percp', '600>>600>>550', 'uid/gid/ugo校验结果正常!', 'PASSED'],
['/thdfq_khsfb/model', '600>>600>>550', 'uid/gid/ugo校验结果正常!', 'PASSED'],
['/thdfq_khsfb/kznameq_bjzdkmmty', '600>>600>>550', 'uid/gid/ugo校验结果正常!', 'PASSED'],
['/thdfq_plt/hjadernk_service', '600>>600>>550', 'uid/gid/ugo校验结果正常!', 'PASSED'],
['/thdfq_plt/hjadernk', '600>>600>>555', 'uid/gid/ugo校验结果正常!', 'PASSED'],
['/thdfq_plt/thdfqos', '600>>600>>550', 'uid/gid/ugo校验结果正常!', 'PASSED'],
['/svp', '200>>200>>550', 'uid/gid/ugo校验结果正常!', 'PASSED'],
['/thdfq_hdmap', '600>>600>>770', 'uid/gid/ugo校验结果正常!', 'PASSED'],
['/thdfq_map/nzpmap', '600>>600>>770', 'uid/gid/ugo校验结果正常!', 'PASSED'],
['/thdfq_map/parkingmap', '600>>600>>777', 'uid/gid/ugo校验结果正常!', 'PASSED'],
['/thdfq_para/bjzdkmmty', '700>>201>>770', 'uid/gid/ugo校验结果正常!', 'PASSED'],
['/thdfq_para/swk', '700>>201>>775', 'uid/gid/ugo校验结果正常!', 'PASSED'],
['/thdfq_knvr/ota_cache', '200>>200>>775', 'uid/gid校验结果异常!预期值为700、201', 'FAILED'],
['/thdfq_knvr/logs', '600>>600>>777', 'uid/gid/ugo校验结果正常!', 'PASSED'],
['/thdfq_knvr/mja', '600>>600>>770', 'uid/gid/ugo校验结果正常!', 'PASSED'],
['/thdfq_knvr/eqz', '600>>600>>770', 'uid/gid/ugo校验结果正常!', 'PASSED'],
['/dsv_knvr', '200>>200>>770', 'uid/gid/ugo校验结果正常!', 'PASSED'],
['/thdfq_rawknvr', '600>>600>>770', 'uid/gid/ugo校验结果正常!', 'PASSED']]
return results
def formatted_print():
headers = ["Skds/Public", "UID/GID/UGO", "DetailsInfo", "CheckResult"]
data = query_uid_gid_ugo()
column_widths = [max(len(str(row[i])) for row in data) for i in range(len(headers))]
# print(column_widths)
header_line = "\t|\t".join(half_all(f"{headers[i]:<{column_widths[i]}}") for i in range(len(headers)))
print(header_line)
for row in data:
row_line = "\t|\t".join(half_all(f"{str(item):<{column_widths[i]}}") for i, item in enumerate(row))
print(row_line)
formatted_print()
def query_uid_gid_ugo():
results = [['/thdfq_khsfb/pnc', '600>>600>>550', 'uid/gid/ugo校验结果正常!', 'PASSED'],
['/thdfq_khsfb/map', '600>>600>>550', 'uid/gid/ugo校验结果正常!', 'PASSED'],
['/thdfq_khsfb/percp', '600>>600>>550', 'uid/gid/ugo校验结果正常!', 'PASSED'],
['/thdfq_khsfb/model', '600>>600>>550', 'uid/gid/ugo校验结果正常!', 'PASSED'],
['/thdfq_khsfb/kznameq_bjzdkmmty', '600>>600>>550', 'uid/gid/ugo校验结果正常!', 'PASSED'],
['/thdfq_plt/hjadernk_service', '600>>600>>550', 'uid/gid/ugo校验结果正常!', 'PASSED'],
['/thdfq_plt/hjadernk', '600>>600>>555', 'uid/gid/ugo校验结果正常!', 'PASSED'],
['/thdfq_plt/thdfqos', '600>>600>>550', 'uid/gid/ugo校验结果正常!', 'PASSED'],
['/svp', '200>>200>>550', 'uid/gid/ugo校验结果正常!', 'PASSED'],
['/thdfq_hdmap', '600>>600>>770', 'uid/gid/ugo校验结果正常!', 'PASSED'],
['/thdfq_map/nzpmap', '600>>600>>770', 'uid/gid/ugo校验结果正常!', 'PASSED'],
['/thdfq_map/parkingmap', '600>>600>>777', 'uid/gid/ugo校验结果正常!', 'PASSED'],
['/thdfq_para/bjzdkmmty', '700>>201>>770', 'uid/gid/ugo校验结果正常!', 'PASSED'],
['/thdfq_para/swk', '700>>201>>775', 'uid/gid/ugo校验结果正常!', 'PASSED'],
['/thdfq_knvr/ota_cache', '200>>200>>775', 'uid/gid校验结果异常!预期值为700、201', 'FAILED'],
['/thdfq_knvr/logs', '600>>600>>777', 'uid/gid/ugo校验结果正常!', 'PASSED'],
['/thdfq_knvr/mja', '600>>600>>770', 'uid/gid/ugo校验结果正常!', 'PASSED'],
['/thdfq_knvr/eqz', '600>>600>>770', 'uid/gid/ugo校验结果正常!', 'PASSED'],
['/dsv_knvr', '200>>200>>770', 'uid/gid/ugo校验结果正常!', 'PASSED'],
['/thdfq_rawknvr', '600>>600>>770', 'uid/gid/ugo校验结果正常!', 'PASSED']]
return results
def zh_width(str_val):
try:
count = 0
for word in str_val: # 检测长宽度中文字符
if (word >= '\u4e00' and word <= '\u9fa5') or word in [';', ':', ',', '(', ')', '!', '?', '——', '……', '、','》', '《']:
count += 1
return count
except:
return 0
def formatted_print():
headers = ["Skds/Public", "UID/GID/UGO", "DetailsInfo", "CheckResult"]
data = query_uid_gid_ugo()
column_widths = [max(len(str(row[i])) for row in data) for i in range(len(headers))]
print(column_widths)
# 获取最多有多少个中文
max_zh = [max(zh_width(str(row[i])) for row in data) for i in range(len(headers))]
print(max_zh)
# 前面减去要补的中文空格数,后面再直接追加相应的中文空格
header_line = "\t|\t".join(f"{headers[i]:<{column_widths[i]-(max_zh[i]-zh_width(headers[i]))}}{'':{chr(12288)}<{max_zh[i]-zh_width(headers[i])}}" for i in range(len(headers)))
print(header_line)
for row in data:
row_line = "\t|\t".join(f"{str(item):<{column_widths[i]-(max_zh[i]-zh_width(str(item)))}}{'':{chr(12288)}<{max_zh[i]-zh_width(str(item))}}" for i, item in enumerate(row))
print(row_line)
formatted_print()
中文字符长度问题,可以考虑先encode在计算长度
你没有考虑到中文字符和英文字符的宽度不同。中文字符在终端中通常占据的宽度是一个英文字符的两倍。在计算列宽度时,你需要考虑到字符串中的中文字符。
如果结果全是正常会出现这种情况吗?
额,不好意思题主,我刚刚试了一下,代码逻辑是对的,不过没对齐问题没找到。您要是不介意可以试试用第三方库prettytable来打印,这个可以创建一个表格自动调整列宽。
from prettytable import PrettyTable
def query_uid_gid_ugo():
results = [['/thdfq_khsfb/pnc', '600>>600>>550', 'uid/gid/ugo校验结果正常!', 'PASSED'],
['/thdfq_khsfb/map', '600>>600>>550', 'uid/gid/ugo校验结果正常!', 'PASSED'],
['/thdfq_khsfb/percp', '600>>600>>550', 'uid/gid/ugo校验结果正常!', 'PASSED'],
['/thdfq_khsfb/model', '600>>600>>550', 'uid/gid/ugo校验结果正常!', 'PASSED'],
['/thdfq_khsfb/kznameq_bjzdkmmty', '600>>600>>550', 'uid/gid/ugo校验结果正常!', 'PASSED'],
['/thdfq_plt/hjadernk_service', '600>>600>>550', 'uid/gid/ugo校验结果正常!', 'PASSED'],
['/thdfq_plt/hjadernk', '600>>600>>555', 'uid/gid/ugo校验结果正常!', 'PASSED'],
['/thdfq_plt/thdfqos', '600>>600>>550', 'uid/gid/ugo校验结果正常!', 'PASSED'],
['/svp', '200>>200>>550', 'uid/gid/ugo校验结果正常!', 'PASSED'],
['/thdfq_hdmap', '600>>600>>770', 'uid/gid/ugo校验结果正常!', 'PASSED'],
['/thdfq_map/nzpmap', '600>>600>>770', 'uid/gid/ugo校验结果正常!', 'PASSED'],
['/thdfq_map/parkingmap', '600>>600>>777', 'uid/gid/ugo校验结果正常!', 'PASSED'],
['/thdfq_para/bjzdkmmty', '700>>201>>770', 'uid/gid/ugo校验结果正常!', 'PASSED'],
['/thdfq_para/swk', '700>>201>>775', 'uid/gid/ugo校验结果正常!', 'PASSED'],
['/thdfq_knvr/ota_cache', '200>>200>>775', 'uid/gid校验结果异常!预期值为700、201', 'FAILED'],
['/thdfq_knvr/logs', '600>>600>>777', 'uid/gid/ugo校验结果正常!', 'PASSED'],
['/thdfq_knvr/mja', '600>>600>>770', 'uid/gid/ugo校验结果正常!', 'PASSED'],
['/thdfq_knvr/eqz', '600>>600>>770', 'uid/gid/ugo校验结果正常!', 'PASSED'],
['/dsv_knvr', '200>>200>>770', 'uid/gid/ugo校验结果正常!', 'PASSED'],
['/thdfq_rawknvr', '600>>600>>770', 'uid/gid/ugo校验结果正常!', 'PASSED']]
return results
def formatted_print():
headers = ["Skds/Public", "UID/GID/UGO", "DetailsInfo", "CheckResult"]
data = query_uid_gid_ugo()
table = PrettyTable(headers)
table.align = "l"
for row in data:
table.add_row(row)
print(table)
formatted_print()
一种简单的方法是使用一个自定义的函数来计算字符串的实际宽度,然后根据这个宽度来对齐。例如,您可以定义如下的函数:
def get_width(s): # 计算字符串的实际宽度,中文字符算两个,英文字符算一个 width = 0 for c in s: if ord© > 127: # 判断是否是中文字符 width += 2 else: width += 1 return width
然后在您的formatted_print函数中,使用这个函数来替换原来的column_widths列表:
column_widths = [max(get_width(str(row[i])) for row in data) for i in range(len(headers))]
该回答通过自己思路及引用到GPTᴼᴾᴱᴺᴬᴵ搜索,得到内容具体如下:
根据您提供的代码和截图,您想要实现一个打印对齐的功能,但是目前的结果没有达到预期的上下对齐效果。问题出在您计算每列的最大宽度时,没有考虑到每个中文字符的宽度为2个英文字符。
为了解决这个问题,您可以按照以下步骤进行修改:
1、 引入unicodedata
模块,用于计算字符串长度时考虑中文字符的宽度。
import unicodedata
2、 修改计算列宽的部分,将每个字符的宽度乘以相应的权重,考虑中文字符的实际宽度。
column_widths = [max(max(unicodedata.east_asian_width(str(row[i])) == 'W', len(str(row[i]))) for row in data) * 2 for i in range(len(headers))]
3、 修改打印部分,使用\t
制表符进行对齐,并在每列之间添加竖线分隔符。
header_line = " | ".join(f"{headers[i]:^{column_widths[i]}}" for i in range(len(headers)))
print(header_line)
for row in data:
row_line = " | ".join(f"{str(item):^{column_widths[i]}}" for i, item in enumerate(row))
print(row_line)
这样修改后,您应该能够得到更加对齐的打印结果。请注意,中文字符的宽度在计算时被乘以2,以确保对齐效果正确。
希望这个解决方案能够帮助到您!
如果以上回答对您有所帮助,点击一下采纳该答案~谢谢
我建议用prettytable来
在Python中实现print输出按列对齐的多种方法播
使用%格式按列对齐打印输出
可以参考下
引用gpt作答:
其中一个问题是在计算列宽时未考虑到列标题的长度。由于行的数据中很长的字符串,导致列宽度的计算不准确,从而导致对齐问题。
您可以尝试更改计算列宽的部分,将列标题的长度也考虑在内。这里是修改后的 formatted_print
函数:
def formatted_print():
headers = ["Skds/Public", "UID/GID/UGO", "DetailsInfo", "CheckResult"]
data = query_uid_gid_ugo()
# 计算列宽时考虑到列标题的长度
column_widths = [max(len(item), len(headers[i])) for i, item in enumerate(headers)]
print(column_widths)
# 打印表头
header_line = "\t|\t".join(f"{headers[i]:<{column_widths[i]}}" for i in range(len(headers)))
print(header_line)
# 打印数据行
for row in data:
row_line = "\t|\t".join(f"{str(item):<{column_widths[i]}}" for i, item in enumerate(row))
print(row_line)
formatted_print()
【相关推荐】
#!/usr/bin/env python3
## disk
## shanhai
def shanhai():
import subprocess
cmd = 'lsblk'
disks = {}
ret = subprocess.getoutput(cmd)
for line in ret.splitlines():
if 'disk' in line:
dev_name = line.split()[0]
dev_size = line.split()[3]
disks[dev_name] = dev_size
return disks
ret = shanhai()
for k,v in ret.items():
print("磁盘名称:" + k + "\t" + "总容量:" + v)