Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Automated alignment of "tabular" Python code [closed]

Tags:

python

I have some Python code that looks something like this:

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'))]}

Note that the decimal values are aligned around the decimal point, while the integers are right-aligned.

Is there some software that can perform this kind of complex alignment in an automated fashion? I'd be interested in anything that gets close, even if it can't match the above exactly.

like image 559
mithrandi Avatar asked Dec 22 '22 08:12

mithrandi


2 Answers

(NOTE: I do not consider the following particularly sane.)

For the most part if you just typed out (most editors will help you align your dict and list items) your original code you should get something like this:

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'))]}

(I've made some values longer and some shorter to add a little more quirkiness.)

With the Tabular plugin for Vim, executing the following commands in order over the above code (you may want to visually block it) will format the above code in a way that matches your original question:

:Tab /^[^[(]*\zs[[(]/l0
:Tab /^[^(]*\zs(/l0
:Tab /(\zs\d\+\s*,/l0r1
:Tab /,\s*\zs\d\+)/l1r0
:Tab /['"]\d*\ze\.\d*['"]/l0r0

The operations are:

  1. Align the first [s and (s.
  2. Align the first (s, this fixes the misalignment from the first operation.
  3. Right-align the (17500,-like values on ,.
  4. Right-align the , 99999)-like values on ,.
  5. Align the '4563.00'-like values on ..

You could make a mapping for use in normal and visual mode:

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>

Final result:

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'))]}

Obviously the effectiveness of these operations depends on the structure and original formatting of the code but hopefully this inspires you.

like image 97
Jonathan Avatar answered Jan 02 '23 14:01

Jonathan


While the Standard Library pprint module will add whitespace to make dictionaries and lists at least look reasonable on the screen, I know of nothing that will, for example, consider the periods in string constants to be significant and add enough whitespace to align them! Unless I am far wrong, you will likely always be doing this kind of alignment in Python by hand.

If you store these values in a separate table file that is plain text, then, of course, you will probably find several editors that would be willing to help you align the decimal points.

like image 36
Brandon Rhodes Avatar answered Jan 02 '23 13:01

Brandon Rhodes