views:

425

answers:

3

I need to print escaped characters to a binary file using Ruby. The main problem is that slashes need the whole byte to escape correctly, and I don't know/can't create the byte in such a way.

I am creating the hex value with, basically:

'\x' + char

Where char is some 'hex' value, such as 65. In hex, \x65 is the ASCII character 'e'.

Unfortunately, when I puts this sequence to the file, I end up with this:

\\x65

How do I create a hex string with the properly escaped value? I have tried a lot of things, involving single or double quotes, pack, unpack, multiple slashes, etc. I have tried so many different combinations that I feel as though I understand the problem less now then I did when I started.

How?

A: 

If you have the hex value and you want to create a string containing the character corresponding to that hex value, you can do:

irb(main):002:0> '65'.hex.chr
=> "e"

Another option is to use Array#pack; this can be used if you need to convert a list of numbers to a single string:

irb(main):003:0> ['65'.hex].pack("C")
=> "e"
irb(main):004:0> ['66', '6f', '6f'].map {|x| x.hex}.pack("C*")
=> "foo"
Brian Campbell
That prints the string \x65 to a file called foo.tmp. I need to print binary byte \x65 to a file.
Allyn
Did you see the second half of my answer? '65'.hex.chr will turn the string '65' into the number 101 (0x65), and then turn that into the character "e", which you can the write out. I will add another example of using Array#pack to my answer as well.
Brian Campbell
+3  A: 

You may need to set binary mode on your file, and/or use putc.

File.open("foo.tmp", "w") do |f|
  f.set_encoding(Encoding::BINARY) # set_encoding is Ruby 1.9  
  f.binmode                        # only useful on Windows
  f.putc "e".hex
end

Hopefully this can give you some ideas even if you have Ruby <1.9.

Sarah Mei
+1  A: 

Okay, if you want to create a string whose first byte has the integer value 0x65, use Array#pack

irb> [0x65].pack('U')
#=> "e"
irb> "e"[0]
#=> 101

10110 = 6516, so this works.

If you want to create a literal string whose first byte is '\', second is 'x', third is '6', and fourth is '5', then just use interpolation:

irb> "\\x#{65}"
#=> "\\x65"
irb> "\\x65".split('')
#=> ["\\", "x", "6", "5"]
rampion