How can I convert "1234567890" to "\x12\x34\x56\x78\x90" in Ruby?
-
Judging by the answers, the output is supposed to be "\x12\x34\x56\x78\x90", rather than an Array of Fixnum or a syntactically invalid Hash.Martin Dorey– Martin Dorey2013-07-26 20:55:48 +00:00Commented Jul 26, 2013 at 20:55
Add a comment
|
6 Answers
Try this:
["1234567890"].pack('H*')
1 Comment
Niklas B.
This is definitely the most elegant solution. The top voted answer will not do what is asked.
Ruby 1.8 -
hex_string.to_a.pack('H*')
Ruby 1.9 / Ruby 1.8 -
Array(hex_string).pack('H*')
3 Comments
neoneye
File.open('output.txt', 'w+') {|f| f.write(IO.read('input.txt').to_a.pack('H*')) }
ZombieDev
I'm not sure how your answer is supposed to work. Could you give a better example using the hex string in the question? When I tried your code I got:
d:\>irb irb(main):001:0> hex_string = "1234567890" => "1234567890" irb(main):002:0> hex_string.to_a.pack('H*') NoMethodError: undefined method to_a' for "1234567890":String from (irb):2 from C:/Ruby192/bin/irb:12:in <main>' irb(main):003:0>Vikrant Chaudhary
@ZombieDev, @steenslag Ruby 1.9 doesn't have
String#to_a method. I've updated my answer to reflect that.Assuming you have a well-formed hexadecimal string (pairs of hex digits), you can pack to binary, or unpack to hex, simply & efficiently, like this:
string = '0123456789ABCDEF'
binary = [string].pack('H*') # case-insensitive
=> "\x01#Eg\x89\xAB\xCD\xEF"
hex = binary.unpack('H*').first # emits lowercase
=> "012345679abcdef"
Comments
class String
def hex2bin
s = self
raise "Not a valid hex string" unless(s =~ /^[\da-fA-F]+$/)
s = '0' + s if((s.length & 1) != 0)
s.scan(/../).map{ |b| b.to_i(16) }.pack('C*')
end
def bin2hex
self.unpack('C*').map{ |b| "%02X" % b }.join('')
end
end
1 Comment
Joshua Pinter
Can you explain what the validation REGEX does?
If you have a string containing numbers and you want to scan each as a numeric hex byte, I think this is what you want:
"1234567890".scan(/\d\d/).map {|num| Integer("0x#{num}")}
2 Comments
the Tin Man
I'd have done: "1234567890".scan(/\d\d/).map {|i| i.to_i(16) }
Huw Walters
Or, to handle hex characters as requested,
"1234567890abcdef".scan(/[0-9A-Fa-f]{2}/).map { |i| i.to_i(16) }.