Gsub and \\\\

Hi,

I'm probably being dense, but -

"ab\\cd".gsub(/\\/, "\\\\")

=> "ab\\cd"

I expected the above to produce "ab\\\\cd"

If i add a character in between the \\\\, then
I do get two backslashes in the result:

"ab\\cd".gsub(/\\/, "\\a\\")

=> "ab\\a\\cd"

If I add a third backslash in the replacement string,
then I get two in the result:

"ab\\cd".gsub(/\\/, "\\\\\\")

=> "ab\\\\cd"

Is this the expected behavior? If so, what's the
principle I need to know to understand it? :slight_smile:

(ruby 1.8.2 (2004-07-29) [i386-mswin32] and
ruby 1.8.2 (2004-11-06) [i686-linux])

Thanks,

Regards,

Bill

Bill Kelly wrote:

I'm probably being dense, but -

"ab\\cd".gsub(/\\/, "\\\\")

Here's the details, this comes up frequently:

..gsub adds its own layer of escaping. \1 refers to the first match, \2 to the second and there is also stuff like \'. (In general those forms are equivalent to global variables. E.g. \1 => $1)

Because Ruby's String literals already have one level of escaping you have to escape everything two times which is confusing.

You can do the above like this:

"ab\\cd".gsub(/\\/) { "\\\\" } # replaces one slash with two
"ab\\cd".gsub(/\\/, "\\\\\\\\" } # same

Of course having that meta layer available can make sense when you don't want to use a block:

"foobar quxquv".gsub(/\w(\w+)/, "\\1") # or in most cases also
"foobar quxquv".gsub(/\w(\w+)/, '\1') # but note that
"foobar quxquv".gsub(/\w(\w+)/, '\\\\') # replace with one slash

Personally I'd like this mess to be fixed by using $ instead of \ for the escaping layer of .gsub. That would yield code like this:

"foobar quxquv".gsub(/\w(\w+)/, "$1")
"ab\\cd".gsub(/\\/, "\\\\")
"Give me $1".gsub("$1", "$$2") # dollar needs to be escaped, new case

I don't know if matz also thinks that the latter version would be better than the current one, but even if it is like that there's still the problem of compatibility...

elathan@velka:~> ruby -e 'puts "a\\b"'
a\b

Adios,

···

On Thu, Jan 20, 2005 at 03:11:46AM +0900, Bill Kelly wrote:

Hi,

I'm probably being dense, but -

>> "ab\\cd".gsub(/\\/, "\\\\")
=> "ab\\cd"

--
University of Athens I bet the human brain
Physics Department is a kludge --Marvin Minsky

Florian Gross wrote:

"ab\\cd".gsub(/\\/, "\\\\\\\\" } # same

Sorry, that should have been "ab\\cd".gsub(/\\/, "\\\\\\\\") of course.

Bill Kelly wrote:

> I'm probably being dense, but -
>
>>>"ab\\cd".gsub(/\\/, "\\\\")

Here's the details, this comes up frequently:

..gsub adds its own layer of escaping. \1 refers to the first match, \2
to the second and there is also stuff like \'. (In general those forms
are equivalent to global variables. E.g. \1 => $1)

Because Ruby's String literals already have one level of escaping you
have to escape everything two times which is confusing.

Argh! Thanks....!! I used to know this... :slight_smile:

Regards,

Bill

···

From: "Florian Gross" <flgr@ccan.de>

"Florian Gross" <flgr@ccan.de> schrieb im Newsbeitrag
news:357nbmF4j4bmmU1@individual.net...

Bill Kelly wrote:

> I'm probably being dense, but -
>
>>>"ab\\cd".gsub(/\\/, "\\\\")

Here's the details, this comes up frequently:

In fact we could make this thread sticky - if that were possible with news
and mail readers. :slight_smile:

Just to add one point to your excellent explanation: Another source of
confusion in this context is irb which uses String#inspect which in turn
adds escaping again:

irb(main):001:0> s = "a\\b"
=> "a\\b"
irb(main):002:0> puts s
a\b
=> nil

Kind regards

    robert

Because Ruby's String literals already have one level of escaping you have to escape everything two times which is confusing.

Could you please give some more details? I still do not understand
how gsub works...

irb(main):101:0* puts "aa\\bb".gsub(/\\/, "\\")
aa\bb
=> nil
irb(main):102:0> puts "aa\\bb".gsub(/\\/, "\\\\")
aa\bb
=> nil
irb(main):103:0> puts "aa\\bb".gsub(/\\/, "\\\\\\")
aa\\bb
=> nil
irb(main):104:0> puts "aa\\bb".gsub(/\\/, "\\\\\\\\")
aa\\bb
=> nil
irb(main):105:0> puts "aa\\bb".gsub(/\\/, "\\\\\\\\\\")
aa\\\bb
=> nil
irb(main):106:0> puts "aa\\bb".gsub(/\\/, "\\\\\\\\\\\\")
aa\\\bb
=> nil
irb(main):107:0> puts "aa\\bb".gsub(/\\/, "\\\\\\\\\\\\\\")
aa\\\\bb
=> nil

···

--
   s&g