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
Related
I tried to execute a calculation in Ruby. The result I get is 1589.5833333333333. I would like to limitat the numbers of digits after the comma.
The result should always be limited to 2 digits as followed:
1589.58
Question #1 = how can I set the limitation?
Question #2 = how can I round up 1589.60 or down 1589.55
Many thanks for help. Language is ruby
Other option but keeping the object as Float:
n = 1589.5833333333333
m = n.truncate(2) #=> 1589.58
h = n.round(1) #=> 1589.6 # for the last zero you need to format the string
And a tricky:
k = (n*100).to_i.digits.tap{ |ary| ary.first > 5 ? ary[0] = 5 : ary[0] = 0 }.reverse.join('').to_i/100.0
#=> 1589.55
For question 1:
num = 1589.5833333333333
printf('%.2f', num)
=> 1589.58
For question 2 to round up to first digit:
num = 1589.5833333333333
printf('%.2f', num.round(1))
=> 1589.60
1589.55 is a bit of an arbitrary number, rounding down would usually be calculated as 1589.58. I don't know of any Ruby function that does that off-hand.
I have try to match some conditions for
each letter instance in a string may only participate in one match.
if a letter instance can participate in either n1 or n2, it is to be counted towards n1.
the two strings may or may not be of the same length.
I have try to match on the basis of these conditions bit still getting issue while testing for long string or odd string comparisons.
def matchval_not_pos(str1, str2)
a1, a2 = str1.chars, str2.chars
[a1.size, a2.size].min.times do |i|
if a1[i] == a2[i]
a1.delete_at(i)
a2.delete_at(i)
end
end
a1.reduce(0) do |t,c|
i = a2.index(c)
if i
inc = 1
a2.delete_at(i)
else
inc = 0
end
t + inc
end
end
Some examples (str1, str2 -> n1,n2):
"abc", "abc" -> 3,0
"bca", "abc" -> 0,3
"aab", "abb" -> 2,0
"aab", "aba" -> 1,2
"abc", "aaa" -> 1,0
As I understand, you have two strings, s1 and s2, from which you obtain two strings:
ss1 = s1[0,n]
ss2 = s2[0,n]
where
n = [s1.size, s2.size].min
and you want to know if the characters of ss2 can be rearranged to equal ss1. If my understanding is correct, that would be true if and only if the following is true:
ss1.chars.sort == ss2.chars.sort
Example:
s1 = "ebcda"
s2 = "adcbefr"
n = [s1.size, s2.size].min #=> 5
ss1 = s1[0,n] #=> "ebcda"
ss2 = s2[0,n] #=> "adcbe"
ss1.chars.sort == ss2.chars.sort #=> true
For some reason most Ruby string functions work with predetermined substrings and patterns. I don't have any assumptions about the string's contents, but I need to just delete n chars from m-th position. How do I do that?
str = "abcdefghij"
m = 4
n = 3
str.slice!(m,n) # => "efg"
p str # => "abcdhij"
You can use slice!
str='Apple'
str.slice![1..3] #=> ppl
puts str
#=> Ae
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').
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"