Search code examples
rubystringtype-conversionhbasejruby

Why does Ruby convert integer to octal-escaped string instead of hex-escaped one?


I need:

"ff".hex.chr #=> "\xff"

but instead I get:

"ff".hex.chr #=> "\377"

Where is my mistake? What is missing? Environment is HBase 0.98.6 shell, which seems to be based on JRuby 1.6.8 console.


Solution

  • "\xff" and "\377" are different representations of the same data:

    • "\xff" is hexdecimal, and is typical of newer Ruby versions.
    • "\377" is octal, and is typical of older Ruby versions.

    You can see how the same number produces different strings:

    printf("%o",255) #=> "377"
    printf("%x",255) #=> "ff"
    

    The default representation is a typically due to your console settings and Ruby version.

    In general, do not rely on String#inspect to produce a consistent represenation, even on the same Ruby version. You can see this in action if you use some of the special characters:

    "\007" #=> "\a"
    

    The String#inspect method has altered the representation to neither octal nor hex.

    If you're outputting to a system that requires a specific format, you can be explicit:

    printf("\\x%x", 255) #=> \xff  # lower case
    printf("\\x%X", 255) #=> \xFF  # upper case
    

    You can also try the pack and unpack methods:

    ["ff"].pack("H*") #=> "\xFF"
    

    If your string is always hex digits, and your desired output is just inserting "\x" in front of every two characters, then there's a fast solution:

    print "a1b2c3".gsub(/../){"\\x#{$&}"}
    #=> \xa1\xb2\xc3
    

    A good quick introduction to Ruby string represenations and how to work with unprintable characters is in the Safari Books Ruby Cookbook