http://www.perlmonks.org?node_id=69240

I found myself grovelling through some fixed-width data and I realised that what I needed was one of those funky ASCII rulers to help me count column widths, those things that look like:

1 2 3 4 5 012345678901234567890123456789012345678901234567890

I whipped up something quickly and it does the job, but it's pretty ugly and I'm sure someone can do better either more elegantly and/or in a more compact manner.

The constraints are simple: a sub takes a scalar arg representing the length of the ruler. This number is rounded up to the next multiple of 10. Return the string representing the ruler.

When you get to the hundreds (and I did need a ruler that was 240 wide) it should look like this:

11 12 13 14 15 ...478901234567890123456789012345678901234567890

Golf, anyone?

sub ruler { my($n,$r) = ($_[0], ' '); $r .= ' 'x(10-length).$_ for (1..($n+9)/10); return "$r\n" . '0123456789' x (($n+9)/10) . "0\n"; }

Replies are listed 'Best First'.
Re: ASCII Rulers
by jmcnamara (Monsignor) on Apr 03, 2001 at 15:01 UTC

    I always look at these golf challenges and think "I bet x would be shorter" but it rarely is. Anyway:
    sub ruler { my($n,$r) = (int($_[0]+9)/10, ' '); $r .= sprintf"%10s",$_ for (1..$n); "$r\n" . '0123456789' x $n . "0\n"; }
    The sprintf would save a few strokes in your code but nothing significant. I'll take your word for it that there is a column 0. ;-)

    For shorter rulers I often use a sequence like this which fits on one line and is easy to count::
    123456789_123456789_123456789_123456789_123456789_123456789_


    John.
    --

      I'll take your word for it that there is a column 0. ;-)

      Heh! Point taken (given). Yes there is, because then I used that value as the offset arg for substr.
      --
      g r i n d e r

Re: ASCII Rulers
by petral (Curate) on Apr 03, 2001 at 15:47 UTC
    A couple of minor golfish things, without really changing the algorithm:
    sub ruler { my $n = 9 + shift; chop $n; join "", " ", map(" "x(9-/../).$_, 1..$n), "\n", "0123456789" x $n, "0\n" }
    But for filling exactly to (arg) columns (eg, to avoid wrapping when using $ENV{COLUMNS}):
    sub ruler { my $n = shift; join"", " ", map(" "x(9-/../).$_, 1..$n/10), "\n", map(/.$/g, 0..$n), "\n" }
    update: or (of course) ye olde one-liner:perl -lwe 'print" ",map(" "x(9-/../).$_,1..$ARGV[0]/10),"\n",map/.$/g,0..shift' further update: chipmunk got it.  He's almost using printf as a map!

    p
Re: ASCII Rulers
by chipmunk (Parson) on Apr 03, 2001 at 21:31 UTC
    61 characters in the body of this subroutine:
    sub ruler { printf$".'%10s'x($l=(9+pop)/10)."$/0".1234567890x$l.$/,1..$l; }
Re: ASCII Rulers
by jmcnamara (Monsignor) on Apr 03, 2001 at 17:05 UTC

    A second attempt (some whitespace remains):
    sub ruler { my $n = ($_[0]+9)/10; (sprintf" "."%10s"x$n."\n",1..$n).'0123456789'x$n."0\n"; }
    As a one liner (75 bytes):
    perl -e'$n=(9+shift)/10;printf" "."%10s"x$n."\n%s0\n",1..$n,"012345678 +9"x$n'


    John.
    --

Re: ASCII Rulers
by MrNobo1024 (Hermit) on Apr 03, 2001 at 19:43 UTC
    sub ruler { my$r=($_[0]+9)/10;" @{[map{sprintf'%9s' ,$_}1..$r]}\n0".1234567890x$r."\n" }
Re: ASCII Rulers
by Tyke (Pilgrim) on Apr 03, 2001 at 17:02 UTC
    This is another approach that might not be shorter, but does work with ruler lengths that aren't a multiple of 10. Update: Just noticed that petral does it more neatly.
    #!perl -w use strict; print ruler(@ARGV); sub ruler { my ($x,$y) = (' ', ''); map{$x.=sprintf('%10d',$_/10) if $_%10 == 0 && $_ != 0; $y.=$_%10} ( +0..$_[0]); return "$x\n$y\n"; }
    I would have liked to use for rather than map, but I couldn't get the 1 line version to compile ;-(

    I also can't get it to work with non-positive integer values ;-((.