From: Robert Klemme Date: 2010-11-23T04:25:27+09:00 Subject: Re: gsub and backslashes On 22.11.2010 18:21, Ammar Ali wrote: > On Mon, Nov 22, 2010 at 3:53 PM, Robert Klemme > wrote: >> On Mon, Nov 22, 2010 at 1:28 PM, Ammar Ali wrote: >>> >>> Actually, 3 backslashes will yield one backslash. The first two result >>> in one (escaped), and the third one, escaped by the previous escaped >>> backslash ends up being one. My second example showed this, using 6 >>> backslashes instead of 8. Using 4 backslashes works because the second >>> pair yields and escaped backslash, but it is not necessary. >> >> That does not work reliably under all circumstances though: >> >> irb(main):006:0> "abc".gsub /./, "\\\n" >> => "\\\n\\\n\\\n" >> irb(main):007:0> puts("abc".gsub /./, "\\\n") >> \ >> \ >> \ >> => nil >> irb(main):008:0> "abc".gsub /./, "\\\\n" >> => "\\n\\n\\n" >> irb(main):009:0> puts("abc".gsub /./, "\\\\n") >> \n\n\n >> => nil > > I think these examples are somewhat misleading, because the escaped > newline (\n) normally includes a backslash. Taking that into account, > i.e. not counting the one that is part of newline character, the first > example is only using 2 backslashes, and the second example is using > 3. The same goes for its friends, \a, \r, \f, etc. That is the very point of my posting: you cannot always use three slashes reliably because - ooops - all of a sudden the last one may be part of something else. In other case, it happens to work irb(main):002:0> "abc".gsub /./, "\\\y" => "\\y\\y\\y" irb(main):003:0> "abc".gsub /./, "\\\\y" => "\\y\\y\\y" Now if someone changes "y" to "n" in the first case the (probably unintended) effect is dramatic. Or consider a replacement string 'foo \1 bar' which at some point in time is changed to "foo \1 bar \n" unsuspectingly and which suddenly does not only yield a newline but some weird octal character. This would have been avoided if the original string did contain two backslashes already. >> It is safer to use 4 backslashes. This is the only robust way to do >> this even though sometimes you can simply use a single backslash (e.g. >> \1 instead of \\1) because string parsing is a bit tolerant under some >> circumstances: > > I don't think this is tolerance from the string parser, it is > recognition of the \1 as a valid octal value. > >> irb(main):014:0> '\1' >> => "\\1" >> irb(main):015:0> '\\1' >> => "\\1" > > Here the single quotes are coming into play. Octal escapes are not > recognized within them. But it outputs the string in double quotes, > "forcing" the backslash to be escaped in the output. Backslashes need > to be escaped in single quoted string, just like they do in double > quoted ones, so in the second example ('\\1'), it's just one > backslash, again. Apparently I was not clear enough. The point is, that there is some tolerance. Both sequences (line 14 and 15) produce the *same* output although they differ in backslash usage. This does not work if you try to write '\' to get a single backslash. For that you need '\\'. If you use two backslashes in both cases it's clear what happens and there is no room for errors. >> but >> >> irb(main):019:0> "\n" >> => "\n" >> irb(main):020:0> "\\n" >> => "\\n" >> irb(main):021:0> "\1" >> => "\x01" >> irb(main):022:0> "\\1" >> => "\\1" > > Here the double quotes are taking effect. The first correctly prints a > newline, the second an escaped one, This is not an "escaped newline" but merely a backslash followed by character "n". Whether that is considered "escaped" in some way depends on the code that processes this string. If at all this is an escaped "n". :) > the third gets recognized as an > octal escape, and the last escapes the meaning of the backslash that > would otherwise cause the 1 to be interpreted as an octal value. Correct. > Maybe using 4 backslashes is safer, overall, but I wouldn't make it a > rule. At least not without explaining these special cases that include > a leading backslash in their normal representation. My precise reason to make it a rule is that it is simple and beginners do not have to remember all these special cases that you find so worthy mentioning. Actually I do not like those special cases and would rather suggest to remove them since they make things unnecessary complicated. The repeated occurrence of newbie confusion and the very discussion we are having here proves that the logic creates more confusion than clarity. The only reason I do not suggest to change this is the fact that this might break a lot of code. Kind regards robert -- remember.guy do |as, often| as.you_can - without end http://blog.rubybestpractices.com/