“表格”Python代码的自动对齐

4 投票
5 回答
1681 浏览
提问于 2025-04-17 03:37

我有一些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

这些操作包括:

  1. 对齐第一个 [(
  2. 对齐第一个 (,这可以修正第一步操作带来的不对齐问题。
  3. 把类似 (17500, 的值右对齐到 ,
  4. 把类似 , 99999) 的值右对齐到 ,
  5. 把类似 '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'))]}

显然,这些操作的效果取决于代码的结构和原始格式,但希望这能给你一些启发。

撰写回答