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 1
s 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"