• How to properly backslash-escape string in Ruby.

    From niemda@21:1/5 to All on Wed Jan 4 18:47:25 2017
    Hello,

    How do I properly convert ruby string into backslash-escaped string? The
    source is base64-encoded value and result should be escaped, so some
    charaters must be encoded as '\xnn'.

    Example:
    Input is 'tracking@c3BlYw==.service' and expected result
    is 'tracking@c3BlYw\x3d\x3d.service'.

    I've already invented the wheel by hacking some conversion routine to do
    this and tried eval (not in production code, the problem mainly exists
    in specs).

    --
    Vladimir
    There is no matter where you are, everyone is connected

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Robert Klemme@21:1/5 to niemda on Wed Jan 4 23:19:15 2017
    On 04.01.2017 19:47, niemda wrote:

    How do I properly convert ruby string into backslash-escaped string? The source is base64-encoded value and result should be escaped, so some charaters must be encoded as '\xnn'.

    Example:
    Input is 'tracking@c3BlYw==.service' and expected result
    is 'tracking@c3BlYw\x3d\x3d.service'.

    I've already invented the wheel by hacking some conversion routine to do
    this and tried eval (not in production code, the problem mainly exists
    in specs).

    I have no idea why someone would need to use eval() to implement this.
    Here's a fairly straightforward approach:

    CONVERSIONS = {
    "=" => "\\x3d",
    }

    def CONVERSIONS.apply(s)
    s.each_char.map {|ch| self[ch] || ch}.join
    end

    irb(main):010:0> CONVERSIONS.apply 'tracking@c3BlYw==.service'
    "tracking@c3BlYw\\x3d\\x3d.service"

    Note that the double backslashes are an artifact of the way #inspect
    works. There are just single backslashes in the string.

    irb(main):011:0> puts CONVERSIONS.apply 'tracking@c3BlYw==.service' tracking@c3BlYw\x3d\x3d.service
    nil

    You can also do

    def CONVERSIONS.apply(s)
    s.gsub(Regexp.union(keys)) {|ch| self[ch]}
    end

    irb(main):016:0> CONVERSIONS.apply 'tracking@c3BlYw==.service'
    "tracking@c3BlYw\\x3d\\x3d.service"

    Although this is slightly inefficient since the Regexp does not change
    as long as the Hash does not change. This could be remedied by freezing
    the Hash and storing the Regexp in another constant or member of
    CONVERSIONS. Or you can use a fixed regex

    def CONVERSIONS.apply(s)
    s.gsub(/./) {|ch| self[ch] || ch}
    end

    Here's another variant:

    def CONVERSIONS.apply(s)
    s.each_char.inject("") {|str, ch| str << (self[ch] || ch)}
    end

    Kind regards

    robert

    --
    remember.guy do |as, often| as.you_can - without end http://blog.rubybestpractices.com/

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)