Home > Blockchain >  How to replace 0's with 1's and vice versa in Ruby
How to replace 0's with 1's and vice versa in Ruby

Time:11-30

Given I have a 32 bit integer: 00000000000000000000000000001001, I'd like to replace all 0's with 1's and vice versa.

Can you please let me know how can I go about the same in Ruby via an appropriate regex expression or otherwise?

Thank you.

CodePudding user response:

If you have a number, use xor to flip the bits. If you actually have a string, use String#tr:

str     = '00000000000000000000000000001001'
flipped = str.tr('01', '10')
# '11111111111111111111111111110110'

CodePudding user response:

Ruby has the unary operator ~ which makes a one's complement. In your case, your 32bit binary integer is decimal 9, so you can do a

~9

to get the bits reversed.

CodePudding user response:

You can use the XOR operator (^) with your string (converted to an integer) and the max 32 bit integer (binary: 0b11111111111111111111111111111111; decimal: 4294967295; hexadecimal: 0xffffffff I'll use 0xffffffff for clarity and conciseness).

The binary XOR (exclusive or) operation works on each pair of bits (in the same location from each number). XOR results in 0 if the bit values are the same and 1 if the bit values differ. So when one of the operands has bit values of 1 in every position, the result is inverted bits from the other operand. This is because all 1 values from the first operand (your number) match their corresponding bit values in the second (the all 1s value) and therefore result in 0. All the 0 values from the first operand differ from corresponding bit values in the second and become 1.

For example, 0b01 ^ 0b11 gives 0b10. The first bit pair is 0 and 1, which differ so the resulting bit is 1. The second pair of bits is 1 and 1, which are the same so the result is 0.

Example:

def replace_bits(int_str)
    (int_str.to_i(2) ^ 0xffffffff).to_s(2).rjust(32, "0")
end
replace_bits("00000000000000000000000000001001")
# => "11111111111111111111111111110110"

Note that you'd have to do a bit more work to get this to work for sizes other than 32 bits.

If you just have an integer rather than a string, this can be simplified to:

def replace_bits(i)
    i ^ 0xffffffff
end
replace_bits(0b00000000000000000000000000001001)
# => 4294967286
replace_bits(0b00000000000000000000000000001001).to_s(2).rjust(32, "0")
# => "11111111111111111111111111110110"

CodePudding user response:

Well, if we try to manipulate this as a string, we can't directly replace all instances of 0 with 1 or we won't be able to switch it back.

So we use an intermediate transformation. Here's a simple implementation.

irb(main):001:0> s = "00000000000000000000000000001001"
irb(main):002:0> s.gsub("1", "0")
=> "00000000000000000000000000000000"
irb(main):003:0> s.gsub("1", "x")
=> "0000000000000000000000000000x00x"
irb(main):004:0> s.gsub("1", "x").gsub("0", "1").gsub("x", "0")
=> "11111111111111111111111111110110"
irb(main):005:0>

CodePudding user response:

a = '00000000000000000000000000001001'
a.each_char.map { |c| c == '0' ? '1' : '0' }.join
# => "11111111111111111111111111110110"

CodePudding user response:

Using String#gsub with a regular expression and a block is very powerful:

s1 = "00101"
s2 = s1.gsub(/[01]/) { |m| m.to_i ^ 1 }   # "11010"

CodePudding user response:

I assume that you want to work with strings only not doing bitwise operations over numbers in this case

The easy way is usign gsub and pass a block where you define the tricky operation like this:

"00000000000000000000000000001001".gsub(/./) do |d|
  if d == "0"
    "1"
  else
    "0"
  end
end

this returns exactly what you want:

=> "11111111111111111111111111110110"
  • Related