# Monkey patching class String to add bitwise operators

**URL:** <https://www.ruby-forum.com/t/monkey-patching-class-string-to-add-bitwise-operators/203591>\
**Category:** Ruby\
**Created:** [February 23, 2011, 11:12am UTC](https://www.ruby-forum.com/t/monkey-patching-class-string-to-add-bitwise-operators/203591 "2011-02-23T11:12:22Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![dubstep](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/cdc98d/32.png) [@dubstep](https://www.ruby-forum.com/u/dubstep)\
**Post date:** [February 23, 2011, 11:12am UTC](https://www.ruby-forum.com/t/monkey-patching-class-string-to-add-bitwise-operators/203591/1 "2011-02-23T11:12:22Z")

</div>

Hello all,

Unfortunately Ruby don’t have bitwise operators for Class String like  
Perl do. I am hoping very much that such operators will be implemented  
in Ruby one day at a low level so they will fast! But until such a day,  
I will roll my own crude operators by monkey patching Class String.  
However, I am experiencing a peculiar error from my Unit Tests:

Loaded suite ./test\_bits  
Started  
…F.  
Finished in 0.000661 seconds.

1. Failure:  
test\_Bits\_XOR\_with\_equal\_length\_returns\_correctly(TestBits)  
[./test\_bits.rb:27]:  
\<“00110001”\> expected but was  
\<“\x00\x00\x01\x01\x00\x00\x00\x01”\>.

6 tests, 9 assertions, 1 failures, 0 errors, 0 skips

Test run options: --seed 36958

Code:

# Monkey patching Class String to add bitwise operators.

# Behaviour matching Perl’s:

# [perlop - Perl operators and precedence - Perldoc Browser](http://perldoc.perl.org/perlop.html#Bitwise-String-Operators)

class String

# Method that performs bitwise AND operation where bits

# are copied if they exists in BOTH operands. If the operand

# sizes are different, the & operator methods acts as though

# the longer operand were truncated to the length of the shorter.

def &(str)  
new = “”

```
(0 ... [self.length, str.length].min).each do |i|
  new << (self[i].ord & str[i].ord)
end

new

```

end

# Method that performs bitwise OR operation where bits

# are copied if they exists in EITHER operands. If the operand

# sizes differ, the shorter operand is extended with the terminal

# part of the longer operand.

def |(str)  
new = “”

```
min = [self.length, str.length].min

(0 ... min).each do |i|
  new << (self[i].ord | str[i].ord)
end

if self.length > str.length
  new << self[min ... self.length]
elsif self.length < str.length
  new << str[min ... str.length]
end

new

```

end

# Method that performs bitwise XOR operation where bits

# are copied if they exists in ONE BUT NOT BOTH operands.

def ^(str)  
new = “”

```
(0 ... [self.length, str.length].min).each do |i|
  new << (self[i].ord ^ str[i].ord)
end

new

```

end  
end

Tests:

#!/usr/bin/env ruby

require ‘bits’  
require ‘test/unit’  
require ‘pp’

class TestBits \< Test::Unit::TestCase  
def test\_Bits\_AND\_with\_equal\_length\_returns\_correctly  
assert\_equal(“00001100”, “00111100” & “00001101”)  
end

def test\_Bits\_AND\_with\_unequal\_length\_returns\_correctly  
assert\_equal(“JAPH\n”, “japh\nJunk” & ‘_**')  
assert\_equal(“JAPH\n”, '**_’ & “japh\nJunk”)  
end

def test\_Bits\_OR\_with\_equal\_length\_returns\_correctly  
assert\_equal(“00111101”, “00111100” | “00001101”)  
end

def test\_Bits\_OR\_with\_unequal\_length\_returns\_correctly  
assert\_equal(“japh\n”, “JA” | " ph\n")  
assert\_equal(“japh\n”, " ph\n" | “JA”)  
end

def test\_Bits\_XOR\_with\_equal\_length\_returns\_correctly  
assert\_equal(“00110001”, “00111100” ^ “00001101”)  
end

def test\_Bits\_XOR\_with\_unequal\_length\_returns\_correctly  
assert\_equal(“JAPH”, “j p \n” ^ " a h")  
assert\_equal(“JAPH”, " a h" ^ “j p \n”)  
end  
end

So, what is this error I see?

Cheers,

Martin

---

<div class="post-metadata">

**Author:** ![himdel](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/h/c67d28/32.png) [@himdel](https://www.ruby-forum.com/u/himdel)\
**Post date:** [March 3, 2011, 1:43pm UTC](https://www.ruby-forum.com/t/monkey-patching-class-string-to-add-bitwise-operators/203591/2 "2011-03-03T13:43:18Z")

</div>

Sorry for the delayed answer, I have been away.

I fail to see how I can fix my code. Adding chr doesnt do the trick  
(same error):

new \<\< (self[i].ord ^ str[i].ord).chr

Cheers,

Martin

---

<div class="post-metadata">

**Author:** ![himdel](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/h/c67d28/32.png) [@himdel](https://www.ruby-forum.com/u/himdel)\
**Post date:** [February 23, 2011, 11:28am UTC](https://www.ruby-forum.com/t/monkey-patching-class-string-to-add-bitwise-operators/203591/3 "2011-02-23T11:28:19Z")

</div>

On Feb 23, 2011, at 02:12 , Martin H. wrote:

> \<“00110001”\> expected but was  
> \<"\x00\x00\x01\x01\x00\x00\x00\x01"\>.

The first are composed of the chars “0” and “1” (ascii 48/49). The  
second are actual ones and zeros (ascii 0/1):

% ruby19 -e ‘p “\x00\x00\x01\x01\x00\x00\x00\x01”.split(//).map(&:ord)’  
[0, 0, 1, 1, 0, 0, 0, 1]

The problem probably lies with your use of ord w/o chr.

---

<div class="post-metadata">

**Author:** ![himdel](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/h/c67d28/32.png) [@himdel](https://www.ruby-forum.com/u/himdel)\
**Post date:** [March 3, 2011, 4:37pm UTC](https://www.ruby-forum.com/t/monkey-patching-class-string-to-add-bitwise-operators/203591/4 "2011-03-03T16:37:36Z")

</div>

On 3/3/2011 06:43, Martin H. wrote:

> Sorry for the delayed answer, I have been away.
> 
> I fail to see how I can fix my code. Adding chr doesnt do the trick  
> (same error):
> 
> new \<\< (self[i].ord ^ str[i].ord).chr

You can’t just call chr on the result if you want the character to be  
‘0’ or ‘1’.

irb(main):001:0\> ‘0’[0].ord ^ ‘1’[0].ord  
=\> 1

Like Ryan said, the ascii value for the character ‘1’ is actually 49;  
however, you have the value of 1, the number rather than the string.  
You need to add 48 to the result of your operation if you want to  
actually get ‘1’.

irb(main):002:0\> (‘0’[0].ord ^ ‘1’[0].ord) + 48  
=\> 49

You can then call chr on that.

irb(main):003:0\> ((‘0’[0].ord ^ ‘1’[0].ord) + 48).chr  
=\> “1”

Doing this is going to break your other tests though since most of them  
expect to be working with letters instead of numbers.

Your problem appears to be with how you expect to represent “binary”  
strings vs. regular strings. You seem to want strings that look like  
‘1011011’ to actually be converted into bit strings before processing  
and then converted back to “binary” strings after. If you know  
beforehand that you’re going to work with a “binary” string though, you  
can easily avoid all your extra work by using String#to\_i and  
Fixnum#to\_s.

irb(main):004:0\> ‘1011011’.to\_i(2)  
=\> 91  
irb(main):005:0\> ‘1011011’.to\_i(2).to\_s(2)  
=\> “1011011”  
irb(main):006:0\> ‘1011011’.to\_i(2) ^ ‘0000100’.to\_i(2)  
=\> 95  
irb(main):007:0\> (‘1011011’.to\_i(2) ^ ‘0000100’.to\_i(2)).to\_s(2)  
=\> “1011111”

-Jeremy
