I am trying to do bitwise xor 2 ASCII strings of the same length in ruby. I have come to the following:
'A'.unpack('B*').zip('B'.unpack('B*')).map{|a, b| (a.to_i ^ b.to_i).to_s}.pack('b*')
=> "\003"
It works. However, when performing string of 2 or more chars, it behaves wierdly, i think because of the value is too big for Fixnum, see below:
'AA'.unpack('B*').zip('BB'.unpack('B*')).map{|a, b| (a.to_i ^ b.to_i).to_s}.pack('b*')
=> "_\003"
If I stop right after the xor, without the to_s part, I see that it is not doing the bitwise XOR correctly:
'AA'.unpack('B*').zip('BB'.unpack('B*')).map{|a, b| (a.to_i ^ b.to_i)}
=> [1515925259]
Can someone help? Or can someone suggest another way of doing this?
Many thanks
I think you want to unpack with C (8-bit unsigned) rather than B (bit string) since the xor operator ^ operates on numbers rather than strings:
'AA'.unpack('C*').zip('BB'.unpack('C*')).map { |a,b| a^b }.pack('C*')
# => "\x03\x03"
3 is what one would expect from xoring 65 ('A') with 66 ('B').
Related
This question already has answers here:
What is the Ruby <=> (spaceship) operator?
(6 answers)
Closed 4 years ago.
I don't quite understand how this works. I guess a large part of it is because I'm used to C and its low-level data structures, and programming at a higher level of abstraction takes some getting used to. Anyway, I was reading The Ruby Programming Language, and I came to the section about ranges and how you can use the <=> operator as sort of a shorthand for what in C you would have to implement as a sequence of if-else statements. It returns either -1, 0, or 1 depending on the results of the comparison. I decided to try it out with the following statement:
range = 1..100
r = (100 <=> range)
print( r )
The result is an empty string. So my question is, how does this operator work; what data type does it return (I assume the return value is an integer type but I can't say for sure); and finally what is the proper way to use it? Thanks for your time, and sorry if this was already answered (I didn't see it in the listing).
The <=> operator is meant to compare two values that can be compared directly, as in strings to strings or numbers to numbers. It can't magically compare two different things, Ruby doesn't convert for you like that.
As such you need to use it in the right context:
1 <=> 2
# => -1
2 <=> 1
# => 1
1 <=> 1
# => 0
When the two things can't be compared you get nil. Note that this is different from "empty string":
1 <=> '1'
# => nil
That means "invalid comparison". The <=> operator is being nice here because in other situations you get an exception:
1 < '1'
# => ArgumentError: comparison of Integer with String failed
You can also use this operator to make your own Comparable compatible class:
class Ordered
include Comparable
attr_reader :sequence
def initialize(sequence)
#sequence = sequence
end
def <=>(other)
self.sequence <=> other.sequence
end
end
Then you can do this:
a = Ordered.new(10)
b = Ordered.new(2)
[ a, b ].sort
# => [#<Ordered:0x00007ff1c6822b60 #sequence=2>, #<Ordered:0x00007ff1c6822b88 #sequence=10>]
Where those come out in order. The <=> implementation handles how these are sorted, and you can finesse that depending on how complex your sorting rules are.
Using the return values -1, 0, and 1 only as labels describing different states, you can write a condition that depends on the order between two numbers:
case a <=> b
when -1 then # a is smaller than b. Do something accordingly
when 0 then # a equals b. Do something accordingly
when 1 then # a is larger than b. Do something accordingly
end
Or, a use case where you can make use of the values -1, 0, and 1, is when you want to get the (non-negative) difference between two numbers a and b without using the abs method. The following:
(a - b) * (a <=> b)
will give the difference.
Add to the other answers this snippet: The "spaceship operator" returns -1, 0, or 1 so you can use it when comparing items in a .sort call:
events.sort {|x, y| y.event_datetime <=> x.event_datetime}
0 means the two items are the same, 1 means they are different but in the correct sort order, and -1 means they are out of order. The above example reverses x and y to sort into descending order.
In C, the function strcmp() has roughly the same behavior, to fit with qsort(), with the same semantics.
I need to convert the follow 4 byte integer to signed integer, like:
input 65535 value -1
input 65534 value -2
input 65533 value -3
and so on...
I tried the follow:
puts (65533).to_s(16) #=> fffd
puts (65533).to_s(16).unpack('s') #=> doesn't work properly... return 26214
Can someone help me with code above?
Best Regards
You could pack it as as an unsigned integer and then unpack it as a signed integer:
[65535, 65534, 65533].pack('S*').unpack('s*')
#=> [-1, -2, -3]
S / s denote 16-bit integers, you can also use L / l for 32-bit or Q / q for 64-bit.
I'm just doing some algorithms problems out of interest in golang. I understand that in other languages to find the next character alphabetically I can bitshift the character, as a character (I'm thinking of C) is really a number.
So I tried doing
"a" >> 2
Or something to that effect, but there is a type mismatch.
I'd like to know how I can achieve this.
I am not sure where you get the idea that this gives you the 'next character'. This is not true in any language. What 'a' >> 2 does is this:
'a' is interpreted as int32(97) (example)
>> means 'shift X right by Y bits'. Shifting something right by 2 bits is functionally the same as an integer divide by 4. So (x >> 2) == (x / 4). (example)
97 / 4 == 24. The b character has ASCII value 98. So this doesn't get you anywhere near. (example)
More on the bit shifting
Bit shifting is most obvious when considering a number in its binary notation. For the expression z = x >> y, we can note the following:
x(97): 01100001
y(2): 00000010
-------- >>
z(24): 00011000
Note that all the bits in x have simply been moved to the right by two bits. The 1 that fell off the end is dropped.
Similarly, you can 'shift left' (<<). Just like x >> 1 is the same as x / 2, x << 1 is the same as x * 2.
Expression: 5>>1 == 5/2 == 2:
x(5): 00000101
y(1): 00000001
-------- >>
z(2): 00000010
Expression: 5<<1 == 5*2 == 10:
x(5): 00000101
y(1): 00000001
-------- <<
z(10): 00001010
Actually getting the next character
If you want the character directly following 'a', you simply add 1 to it as evidenced in this example.
You're trying to shift a string, not a byte, like #Not_a_Golfer said 'a'>>2 should work fine.
However to get the next character you can do something like:
func nextChar(ch byte) byte {
if ch += 1; ch > 'z' {
return 'a'
}
return ch
}
func main() {
fmt.Println(string(nextChar('a')))
}
Of course it'd be more complex if you need more than a-z support, take a look at the unicode package and this blog post about go strings.
I am simply trying to flip the bits of a character. I can get it into a binary form, but when xoring that data with 0xff it seems to not be giving me what I want.
bin = "a".unpack("b*")[0].to_i # Will give me the binary value (10000110)
flip = bin ^ 0xff # this will give me 9999889, expecting (01111001)
Finally, I want to re-pack it as a "character"...
Any help would be appreciated.
You need to tell Ruby that the unpacked string is binary:
bin = "a".unpack("b*")[0].to_i(2) # => 134
flip = bin ^ 0xff # => 121
flip.to_s(2) # => "1111001"
[flip.to_s(2)].pack("b*") # => "O"
Couple of things:
You probably want unpack('B*'), not b* as b* gives you LSB first.
You probably don't need binary at all ("binary" is just a representation of a number, it doesn't need to be "a binary number" in order to XOR it). So you can do simply:
number = "a".unpack('C*')[0]
flip = number ^ 0xff
new_number = [flip].pack('C*')
or, even:
number = "a".ord
flip = number ^ 0xff
new_number = flip.chr
Oh, and the result should not be "O"
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Xor of string in ruby
I would like to make a XOR calculation between two strings.
irb(main):011:0> a = 11110000
=> 11110000
irb(main):014:0> b = 10111100
=> 10111100
irb(main):015:0> a ^ b
=> 3395084
I would like to do this: "hello" ^ "key"
class String
def ^( other )
b1 = self.unpack("U*")
b2 = other.unpack("U*")
longest = [b1.length,b2.length].max
b1 = [0]*(longest-b1.length) + b1
b2 = [0]*(longest-b2.length) + b2
b1.zip(b2).map{ |a,b| a^b }.pack("U*")
end
end
p "hello" ^ "key"
#=> "he\a\t\u0016"
If this isn't the result you want, then you need to be explicit about how you want to perform the calculation, or what result you expect.
convert both strings to byte arrays (take care with the character encoding, not everything can be represented with ASCII)
pad the shorter array with zeroes, so that they're both same size
for n from 0 to array size: XOR firstarray[n] with secondarray[n], probably store the result to result array
convert result byte array back into a string