in reply to Re: underline variable width column headings
in thread underline variable width column headings

I have been able to underline the column headings using Term::ANSIColor but I am not satisfied with the result. There can be twenty six columns depending on the data, so I want to keep my output width to a minimum. The column header consists of one or two digits (the count of the letter) followed by the letter followed by one or two digits called flank in the code (the count of how many times the letter contacts a different letter). The headers vary in width from five to three characters. The line (32) in question is: push @line, sprintf('%2d%s%-2d', scalar @{$trigraphs{$k}}, $k, scalar keys %{$flanks{$k}}); When I use colored in the format portion of sprintf(), like this: sprintf(colored('%2d%s%-2d', 'underline'), I always get an underline that is five characters wide, which is good when my column header is five characters wide; not so good when the header is only three characters wide. I was forced to go that route because even though I got the correct results with the letter part of the header, like this: colored($k, 'underline'), I was unable to get around the fact that I couldn’t use the %d identifier when I tried to underline what I thought would be numerical values from the scalar part of my code (it still sees $k as letters). If I changed %d to %s and used:
colored(scalar @{$trigraphs{$k}}, 'underline'), and colored(scalar keys %{$flanks{$k}}, 'underline')); Note: the last ) is to match the ( in sprintf().
I could get the underline I want, but the headers no longer lined up with the letter above it’s corresponding letter in the columns. The columns print as they should with three spaces between them. That is my problem, can anyone help? Should anyone want to run the code
#! /usr/bin/perl use strict; use warnings; use Term::ANSIColor; # get cipherText my $txt = do{local $/; <DATA>}; $txt =~ s/\s//go; my @letters = split '', $txt; # create trigraphs my (%trigraphs, %flanks); add_trigraph('-', @letters[0..1]); while(@letters > 2){ add_trigraph(@letters[0..2]); shift @letters; } add_trigraph(@letters[0..1], '-'); # sort by most seen middle character my @sorted_keys = sort{ @{$trigraphs{$b}} <=> @{$trigraphs{$a}} || $a cmp $b } keys %trigraphs; # create columns/lines for(my $i = -1;$i < @{$trigraphs{$sorted_keys[0]}};++$i){ my @line; for my $k (@sorted_keys){ unless($i > -1){ # create header @{$trigraphs{$k}} = sort @{$trigraphs{$k}}; push @line, sprintf('%2d%s%-2d', scalar @{$tri +graphs{$k}}, $k, scalar keys %{$flanks{$k}}); next; } next unless defined $trigraphs{$k}->[$i]; push @line, sprintf(' %s ', $trigraphs{$k}->[$i]); } print "@line\n"; } sub add_trigraph { ++$flanks{$_[1]}->{$_} for @_[0,2]; push(@{$trigraphs{$_[1]}}, join('', @_)); } __DATA__ # elcy pg.73 in P format FDRJN UHVXX URDMD SKVSO PJRKZ DYFZJ XGSRR VTQYR WDARW DFVRK VDRKV TDFSZ ZDYFR DNNVO VTSXS AWVZR

Replies are listed 'Best First'.
Re^3: underline variable width column headings
by quester (Vicar) on Dec 15, 2006 at 07:28 UTC
    The colored(...) function wants a character string argument, so you must call sprintf first to convert your numbers to strings, then colored. This fix works (at least on Linux):
    push @line, colored(sprintf('%2d', scalar @{$trigraphs{$k}}), 'und +erline') . $k . colored(sprintf('%-2d',scalar keys %{$flanks{$k}}), 'underline') +;
      Quester, thank you, your solution helped. I have tried everything I could think of to get a proper variable width underline with no success so I will have to settle for what I’ve got. I get 5 underlines under each heading, but at least the columns line up properly when I use:
      push @line, colored(sprintf('%2d', scalar @{$trigraphs{$k}}), 'underli +ne') . colored(sprintf('%s', $k), 'underline') . colored(sprintf('%-2 +d', scalar keys %{$flanks{$k}}), 'underline');
      What puzzles me is that It’s possible to get the variable width underline that I want when I use:
      push @line, sprintf('%2s%s%-2s', colored(scalar @{$trigraphs{$k}}, 'un +derline'), colored($k, 'underline'), colored(scalar keys %{$flanks{$k +}}, 'underline') );
      I just don’t know how to get it with the columns lining up.
        The columns aren't lining up because the character string returned by colored ($x, "underline") is longer than $x, typically by eight characters. That means that sprintf "%2s", colored(...) will never add an extra space.

        The easiest way that I can think of to handle this is to put in the extra spaces as an explicit extra step, like this:

        push @line, " " x ( 2 - length scalar @{ $trigraphs{$k} } ) . colored( scalar @{ $trigraphs{$k} }, 'underline' ) . colored( $k, 'underline' ) . colored( scalar keys %{ $flanks{$k} }, 'underline' ) . " " x ( 2 - length scalar keys %{ $flanks{$k} } );