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

Greetings,

In a recent project, I needed some code that applied a mask against a bitstring.
I didn't have a clue how to achieve that sort of thing at the time, so the fabulous BrowserUk supplied the following code to XOR and AND the two strings:

my @xored = map { ord } split //, $str1 ^ $str2; my @anded = map { ord } split //, $str1 & $str2;

At the time, I was looking for fast ways of doing things, and I remembered Bit::Vector can do this sort of thing (and a lot more besides), so I came up with the following:

use Bit::Vector; sub gen_xor { my $len = length $_[0]; my $vec1 = Bit::Vector->new_Bin($len, $_[0]); my $vec2 = Bit::Vector->new_Bin($len, $_[1]); $vec2->Xor($vec1, $vec2); $vec2->to_Bin(); } sub gen_and { my $len = length $_[0]; my $vec1 = Bit::Vector->new_Bin($len, $_[0]); my $vec2 = Bit::Vector->new_Bin($len, $_[1]); $vec2->And($vec1, $vec2); $vec2->to_Bin(); } print gen_xor('10011', '01110'), "\n"; print gen_and('10011', '01110'), "\n";

Although I'm happy with both BrowserUk's code and my own version using Bit::Vector, I'd like to see some more ways of doing this, as it's been bugging me :-)

Although the original code that inspired this post only required XOR or AND, I'd also be interested to see two bitstrings NAND'ed too.

Golf, Obfu, or truly useful code, please post below!

Cheers

BazB

Update: Corrected first code section.


If the information in this post is inaccurate, or just plain wrong, don't just downvote - please post explaining what's wrong.
That way everyone learns.

Replies are listed 'Best First'.
Re: XOR, AND or NAND'ing bitstrings.
by pg (Canon) on Jan 27, 2003 at 01:25 UTC
    This is not a full solution for you, but rather some interesting fact.

    You can use bit operations, like & and | directly against bit strings, but you have to make sure those strings have the same length (if not, add 0's to the beginning of the shorter one):
    use strict; my $a = "0" . "1011"; my $b = "10011"; print $a & $b, "\n";#00011 print $a | $b;#11011
    However, ^ and ~ do not work in this way.

    The reason why it works for & and |:
    use strict; print ord("0") & ord("0"), "\n";#48, which is "0" print ord("0") & ord("1"), "\n";#48, which is "0" print ord("1") & ord("0"), "\n";#48, which is "0" print ord("1") & ord("1"), "\n";#49, which is "1" print ord("0") | ord("0"), "\n";#48, which is "0" print ord("0") | ord("1"), "\n";#49, which is "1" print ord("1") | ord("0"), "\n";#49, which is "1" print ord("1") | ord("1"), "\n";#49, which is "1"
    The reason why it does not work for ^:
    use strict; print ord("0") ^ ord("0"), "\n";#0, which is not "0" print ord("0") ^ ord("1"), "\n";#1, which is not "1" print ord("1") ^ ord("0"), "\n";#1, which is not "1" print ord("1") ^ ord("1"), "\n";#0, which is not "0"
Re: XOR, AND or NAND'ing bitstrings.
by jryan (Vicar) on Jan 27, 2003 at 05:13 UTC
    use strict; use warnings; sub nand { my @o = reverse split //, $_[0]; my @l = reverse split //, $_[1]; push @l, 0 while @o > @l; return join '', reverse map { 0+!shift @o || 0+!$_} @l; } print nand('1101','10111');
Re: XOR, AND or NAND'ing bitstrings.
by pg (Canon) on Jan 27, 2003 at 20:17 UTC
    Yet another way to do this (the main point is to put "0b" before a bit string to turn it in a number, and then eval. If you don't like those extra ones got from ~, feel free to chop them by doing a substr):
    use strict; print "or: ", sprintf("%b", eval("0b$ARGV[0] | 0b$ARGV[1]")), "\n"; print "and: ", sprintf("%b", eval("0b$ARGV[0] & 0b$ARGV[1]")), "\n"; print "xor: ", sprintf("%b", eval("0b$ARGV[0] ^ 0b$ARGV[1]")), "\n"; print "not: ", sprintf("%b", ~eval("0b$ARGV[0]")), "\n"; print "nand: ", sprintf("%b", ~eval("0b$ARGV[0] & 0b$ARGV[1]")), "\n";