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

I want to read in data from a binary file in 8 bit chunks. I can get the chunks using the "read" function, but I can not figure out how to show the 1's and 0's of the chunk as an output string.

Another thing I want to be able to do is count the number of 1's and 0's in this 8 bit chunk. I would like to do this with out first converting the chunk into a string like I am looking to do in the firt part of my question.

I have become vaguely familiar with pack and unpack, but after many hours of trying and countless searches on google, I can not figure this out.

Any leads would be appreciated!

TIS

Replies are listed 'Best First'.
Re: Printing, analyzing binary
by Zaxo (Archbishop) on Apr 26, 2004 at 03:31 UTC

    Use the %08b format of sprintf.

    It is easy to count ones and zeros if you do convert to a string (it has to be done to print, anyway). my $zeros = tr/0//; will do fine. Assumes the string is in $_.

    After Compline,
    Zaxo

Re: Printing, analyzing binary
by davido (Cardinal) on Apr 26, 2004 at 04:07 UTC
    I'm assuming that you've already got the file reading part down, so my code just takes the shortcut of having nice 8-bit representable numbers in __DATA__. Given that intro, here's a pack / unpack approach.

    use strict; use warnings; while ( my $num = <DATA> ) { chomp $num; next unless $num; my $bits = unpack "b8", pack "C", $num; my $zeros = $bits =~ tr/0//; my $ones = $bits =~ tr/1//; print <<"OUTPUT"; Decimal: $num \t\tZeros: $zeros Bits: $bits \tOnes: $ones OUTPUT } __DATA__ 1 2 3 4 5 6 7 8 15 31 63 127 255


    Dave

Re: Printing, analyzing binary
by hv (Prior) on Apr 26, 2004 at 09:49 UTC

    There are various tricksy ways of trying to count the number of zeros and ones in a byte, but a lookup table is small and simple:

    my @ones = (0); push @ones, map $_ + 1, @ones for 1 .. 8; my @zeros = map 8 - $_, @ones; ... read($fh, $buf, 1) or die ...; my $val = ord($buf); printf "%08b has %s ones and %s zeros\n", $val, $ones[$val], $zeros[ +$val];

    Hugo

Re: Printing, analyzing binary
by Anomynous Monk (Scribe) on Apr 26, 2004 at 15:19 UTC
    N.B. sprintf("%08b", ord $byte) will only work with 5.6.0 and later. For 5.005_xx, use unpack.

    You can also use the new vector modifier 'v' to avoid the ord (or to output multiple bytes worth at once):

    $ perl5.6.2 -we'$x = "\x01"; printf "%0v8b", $x' 00000001 $ perl5.6.2 -we'$x = "\x01\x02"; printf "%0v8b", $x' 00000001.00000010
    If you want just an uninterrupted stream of digits for the latter, remove the .'s afterward:
    $ perl5.6.2 -we'$x = "\x01\x02"; $binary = sprintf "%0v8b", $x; > $binary =~ tr/.//d; print $binary' 0000000100000010
      Thanks, guys - here is what I ended up doing:
      my $buffer; open INF, $srcfile or die "\nCan't open $srcfile for reading: $!\n"; binmode INF; while (read (INF, $buffer, 1)) { # to string my $bits = unpack("b*", $buffer); # count total length, though = # bits my $tot = length($bits); # count 1s my $num1s = 0; while ($bits =~ /1/g) { $num1s++ }; # count 0s my $num0s = 0; while ($bits =~ /0/g) { $num0s++ }; # print info print "$bits\n"; print "$num1s 1's; $num0s 0's; $tot total length\n"; }
      Something I have encountered during my research is the "vec" function (built in) and the Bit::Vector module. Am I correct to assume that both of these provide some level of functionality meant to easily manage/manipulate a series of bits (or boolean values) that are contained inside of an array? TIA