“表格”Python代码的自动对齐
我有一些Python代码,大概是这样的:
rates = {3: [((17500, 99999), Decimal('23425.00'), Decimal('7234.24'))],
4: [(( 0, 3510), Decimal( '4563.00'), Decimal('5234.00')),
(( 3510, 17500), Decimal('34578.00'), Decimal('3464.50')),
((17500, 99999), Decimal('18268.00'), Decimal('5734.66'))],
5: [((17500, 99999), Decimal('83564.00'), Decimal('3475.60'))]}
注意到小数值是围绕小数点对齐的,而整数则是右对齐的。
有没有什么软件可以自动做到这种复杂的对齐方式?我对任何接近这个效果的东西都感兴趣,即使它不能完全匹配上面的效果。
5 个回答
2
我遇到了同样的问题。管理层希望从一些表格格式的数据中打印出漂亮的报告。
我不想只是用一堆打印语句和“魔法”空格来调整对齐,所以我想出了这个Python函数:
def column(filename, data, indent=0):
"""This function takes a list of lists and produces columized output"""
# get the width of the columns
width = []
for mylist in data:
for count, d in enumerate(mylist):
if count > (len(width)-1):
width.append(len(str(d)))
elif len(str(d)) > width[count]:
width[count] = len(str(d))
# print the data
for mylist in data:
line = '{0:<{indent}}'.format('', indent=indent)
for count, d in enumerate(mylist):
try:
line = '%s%s' % (line, '{0:{w},} '.format(d, w=width[count]))
except ValueError, e:
line = '%s%s' % (line, '{0:{w}} '.format(d, w=width[count]))
filename.write(line)
filename.write('\n')
这个函数并不是完美的,你需要根据自己的需求进行调整。特别是,它现在需要一个列表,因为我想按特定的顺序传入数据,而字典是没有顺序的。
2
这里有段代码,可以实现你想要的功能,按照我的理解是这样的。
这段代码有点“人工”,因为它只适用于你那个特定的字典的结构。
不过,我相信这可以作为一个基础,进一步改进,以便考虑其他需求,比如每个元组中有多个小数实例。
from decimal import Decimal
rates = {3: [(( 500, 999), Decimal('23425.008'), Decimal(' 4.24245'))],
281: [(( 0, 10), Decimal( '4563.00' ), Decimal(' 34.00' )),
(( 3510, 500), Decimal(' 578' ), Decimal(' 464.503' )),
((174500, 19), Decimal(' 68.2' ), Decimal('5734' ))],
54: [(( 93500, 99999), Decimal(' 1564.44' ), Decimal(' 75.60' ))]}
def complex_display(di):
K,I1,I2,D1B,D1P,D2B,D2P = [],[],[],[],[],[],[]
for key,val in di.iteritems():
K.append(len(str(key)))
for (i,j),d1,d2 in val :
I1.append(len(str(i)))
I2.append(len(str(j)))
d1b,d1p = str(d1).split('.') if '.' in str(d1) else (str(d1),'.')
d2b,d2p = str(d2).split('.') if '.' in str(d2) else (str(d2),'.')
D1B.append(len(d1b))
D1P.append(len(d1p))
D2B.append(len(d2b))
D2P.append(len(d2p))
k = '%%%dd: [' % max(K)
fv = "%%s((%%%ds, %%%ds), Decimal('%%%ds.%%-%ds'), Decimal('%%%ds.%%-%ds'))%%s" % (max(I1),max(I2),max(D1B),max(D1P),max(D2B),max(D2P))
def produce(di):
for key,val in sorted(di.iteritems()):
for n,((i,j),d1,d2) in enumerate(val) :
d1b,d1p = str(d1).split('.') if '.' in str(d1) else (str(d1)[0:-2],"")
d2b,d2p = str(d2).split('.') if '.' in str(d2) else (str(d2)[0:-2],"")
yield fv % (' ' if n else k % key,i,j,d1b,d1p,d2b,d2p,']' if n+1==len(val) else '')
return '\n'.join(produce(di))
结果
3: [(( 500, 999), Decimal('23425.008'), Decimal(' 4.24245'))]
54: [(( 93500, 99999), Decimal(' 1564.44 '), Decimal(' 75.60 '))]
281: [(( 0, 10), Decimal(' 4563.00 '), Decimal(' 34.00 '))
(( 3510, 500), Decimal(' 5. '), Decimal(' 464.503 '))
((174500, 19), Decimal(' 68.2 '), Decimal(' 57. '))]
这里没有两个字符 '{' 和 '}',要加上它们会让结果变得复杂很多。如果你想的话,可以自己补充代码来加上它们。
结果是根据键进行排序的。
5
(注意:我觉得以下内容并不是特别合理。)
一般来说,如果你把原来的代码输入出来(大多数编辑器会帮你对齐字典和列表项),你应该能得到类似下面的结果:
rates = {3: [((17500, 199999), Decimal('23425.00'), Decimal('7234.245'))],
4: [((0, 3510), Decimal('4563.00'), Decimal('5234.00')),
((3510, 17500), Decimal('34578.00'), Decimal('464.50')),
((17500, 99999), Decimal('18268.00'), Decimal('5734.66'))],
15: [((17500, 99999), Decimal('83564.00'), Decimal('3475.60'))]}
(我把一些值做得长一些,另一些短一些,以增加一点趣味性。)
使用Vim的Tabular插件,按顺序执行以下命令(你可能想要先选中代码)可以把上面的代码格式化成与你原始问题相匹配的样子:
:Tab /^[^[(]*\zs[[(]/l0
:Tab /^[^(]*\zs(/l0
:Tab /(\zs\d\+\s*,/l0r1
:Tab /,\s*\zs\d\+)/l1r0
:Tab /['"]\d*\ze\.\d*['"]/l0r0
这些操作包括:
- 对齐第一个
[
和(
。 - 对齐第一个
(
,这可以修正第一步操作带来的不对齐问题。 - 把类似
(17500,
的值右对齐到,
。 - 把类似
, 99999)
的值右对齐到,
。 - 把类似
'4563.00'
的值对齐到.
。
你可以为正常模式和可视模式创建一个映射:
noremap <leader>ff :Tab /^[^[(]*\zs[[(]/l0<CR>
\:Tab /^[^(]*\zs(/l0<CR>
\:Tab /(\zs\d\+\s*,/l0r1<CR>
\:Tab /,\s*\zs\d\+)/l1r0<CR>
\:Tab /['"]\d*\ze\.\d*['"]/l0r0<CR>
最终结果:
rates = {3: [((17500, 199999), Decimal('23425.00'), Decimal('7234.245'))],
4: [(( 0, 3510), Decimal( '4563.00'), Decimal('5234.00')),
(( 3510, 17500), Decimal('34578.00'), Decimal( '464.50')),
((17500, 99999), Decimal('18268.00'), Decimal('5734.66'))],
15: [((17500, 99999), Decimal('83564.00'), Decimal('3475.60'))]}
显然,这些操作的效果取决于代码的结构和原始格式,但希望这能给你一些启发。