Path: csiph.com!fu-berlin.de!uni-berlin.de!individual.net!not-for-mail From: Robert Klemme Newsgroups: comp.lang.ruby Subject: Re: How to properly backslash-escape string in Ruby. Date: Wed, 4 Jan 2017 23:19:15 +0100 Lines: 66 Message-ID: References: Mime-Version: 1.0 Content-Type: text/plain; charset=utf-8; format=flowed Content-Transfer-Encoding: 7bit X-Trace: individual.net WSw24Bgk7CVd6oPm7r2r7Am3s6LXdCiGWROIO5X6CL8UdrHAc= Cancel-Lock: sha1:Pq0tXMqD8GMijrgJBorUIQeXHVU= User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Thunderbird/45.5.1 In-Reply-To: Xref: csiph.com comp.lang.ruby:7324 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/