[ILUG] urg...

Niall O Broin niall at linux.ie
Sat Feb 2 16:02:21 GMT 2002


On Fri, Feb 01, 2002 at 06:47:31PM +0000, kevin lyda wrote:

> ok, this is driving me nuts.  i have a string in perl.  let's call it $s.
> now i want to take $s 6 bits at a time and put each 6 bits (plus 32) into
> a byte in $e.  in other words each 3 bytes of $s become 4 bytes in $e.
> 
> anyone else play with bit shifting in perl?  it doesn't seem to be
> working so far.
> 
> this doesn't work and i feel like shooting it at this point:
> 
>     #!/usr/bin/perl
> 
>     $s = shift;
>     $s .= "\0" x ((length($s) % 3)? 3 - (length($s) % 3): 0);
>     $e = "";
>     while (length($s) > 0) {
>         $c = substr($s, 0, 3);
> 	$s = substr($s, 3);
> 	foreach $x (1...4){
> 	    $e .= chr((ord(substr($c, 0, 1)) & 0xfc) + 32);
> 	    $c <<= 6;
> 	}
>     }
>     $d = "";
>     print("original: $s(".length($s).")\nencoded: $e\ndecoded: $d\n");

You've a Perl question, so here's a Perl one line answer which puts the command line
argument recoded into $result. If the argument isn't an integral multiple of
6 bits then the end of the result is undefined, but it'll be right as far as
it goes. Supply decent input :-) or code around it. Pack and unpack are
usually the answer when you're bit munging in Perl though I have to admit
that those terrible twins ALWAYS hurt my head.

Normal human beings may not like this but Perl programmers and Lisp people
should be happy enough with it :-)

#!/usr/bin/perl
$result = pack("B*", "0" . join "0", map { (/^1/ ? "10" : "01") . substr $_, 1 }
               grep($_, split(/(......)/, unpack("B*", $ARGV[0]))));

# This is just a simple test / verification

print "INPUT  ";
for (grep($_, split(/(......)/, unpack("B*", $ARGV[0])))) {
    print "  $_"
}
    
print "\nOUTPUT 0" . (join "0", map { (/^1/ ? "10" : "01") . substr $_, 1 } 
      grep($_, split(/(......)/, unpack("B*", $ARGV[0])))) . "\n";




More information about the ILUG mailing list