http://qs1969.pair.com?node_id=966120

eyepopslikeamosquito has asked for the wisdom of the Perl Monks concerning the following question:

Stumbled on some code today that I didn't like very much. Two possible improved implementations are shown in the test program below. How would you do it?

use strict; use warnings; # Original function. # Given an input string $buf, return a string of its ord values sub old_dump_buf { my $buf = shift; my $out; for (my $x = 0; $x < length($buf); $x++) { $out .= sprintf("%3d ", ord(substr($buf, $x, 1))); } return $out; } # Possible improved implementations follow. How would you do it? sub new_dump_buf_1 { my $buf = shift; return sprintf '%3d ' x length($buf), unpack( 'C*', $buf ); } sub new_dump_buf_2 { my $buf = shift; return join ' ', map { sprintf '%3d', $_ } unpack( 'C*', $buf ); } my $testdata = join '', map { chr } 0..255; my $old = old_dump_buf($testdata); $old =~ s/ +$//; print $old, "\n"; my $new1 = new_dump_buf_1($testdata); $new1 =~ s/ +$//; $new1 eq $old or die "oops old != new1"; my $new2 = new_dump_buf_2($testdata); $new2 eq $old or die "oops old != new2";

Replies are listed 'Best First'.
Re: Function to produce formatted ord values of a string
by BrowserUk (Patriarch) on Apr 20, 2012 at 09:43 UTC

    Personally, if the application permitted it, I'd go for:

    sub ords{ sprintf "%02x " x length($_[0]), unpack 'C*', $_[0]; }

    In addition to being a bit quick, I find the shorter dumps using hex more useful.

    If I was really after ultimate speed and the strings to be dumped were of some reasonable maximum length, then I might consider using:

    { my $t = '%02x ' x 1000; sub ords2{ sprintf substr( $t, 0, length $_[0]*5 ), unpack 'C*', $_[0]; } }

    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.

    The start of some sanity?

Re: Function to produce formatted ord values of a string
by jwkrahn (Abbot) on Apr 20, 2012 at 09:02 UTC
    my $testdata = join '', map chr, 0..255; ( my $old = $testdata ) =~ s/(.)/ sprintf '%3d', ord $1 /seg; $old =~ s/ +$//; print "$old\n";
Re: Function to produce formatted ord values of a string
by rovf (Priest) on Apr 20, 2012 at 08:08 UTC

    I would do it like new_dump_buf_2, but would replace unpack by

    split(//,$buf)
    simply because I find it more readable. But it's a matter of taste. People used to unpack might find your code better readable...

    -- 
    Ronald Fischer <ynnor@mm.st>
      Tell me if I'm wrong: I think it's dangerous to use split (character vs byte, unicode). With unpack it's less ambiguous.
        Well, given the sprintf format specification you are using, Unicode is not forseen anyway in your code, but in general: I don't see, why split should be unsafe (it operates on characters, which includes unicode characters), while unpack operates on bytes. Hence, maybe it is unpack which is dangerous, but since I don't have experience with unpack, I leave this question to more knowledgable monks...

        -- 
        Ronald Fischer <ynnor@mm.st>
Re: Function to produce formatted ord values of a string
by GrandFather (Saint) on Apr 20, 2012 at 12:52 UTC

    Being as this is Perl we are using I'd ponder using a regular expression:

    sub new_regex { my $buf = shift; $buf =~ s/(.)/sprintf '%3d ', ord($1)/ge; chop $buf; return $buf; }

    The chop is needed for the test to remove a trailing space and may not be needed in a "real" application.

    True laziness is hard work
Re: Function to produce formatted ord values of a string
by Anonymous Monk on Apr 20, 2012 at 08:30 UTC
    If the speed really matter, then go with this:
    sub new_dump_buf_3 { my $buf = shift; sprintf q{%3d } x (length($buf) - 1) . q{%3d}, unpack 'C*', $buf; }
Re: Function to produce formatted ord values of a string
by Anonymous Monk on Apr 20, 2012 at 08:41 UTC

    From unpack  sub ordinal { unpack("W",$_[0]); } # same as ord()

    So  sub ords { pack '(A4)*', unpack 'W*', @_ } though this only pads spaces to the right, and truncates