From: "Michael W. Ryder" <_mwryder@...> Date: 2007-07-21T04:05:04+09:00 Subject: Re: Is there a replacement for sub? Martin DeMello wrote: > On 7/20/07, Michael W. Ryder <_mwryder@worldnet.att.net> wrote: >> >> Except where you use b = a.sub!(' ', ''). Then if you loop through this >> statement 10 times b is nil, not the abcdef I expected. This is what is >> so confusing. At the same time I can not use b = a.sub(' ', '') as it >> always returns ab c d e f regardless of how many times I execute it, >> which is what I would expect. So, how would I do this? >> 10.times { b = a.sub!(' ', '')} doesn't work, it errors out. > > Remember that a variable is not an object, it is just a label pointing > to an object. > > sub: returns a *copy* of the string, with the substitution made (i.e. > a new object) > sub!: modifies the string in place (i.e. modifies the object itself) > > Therefore > > a = "a b c d e f" > a.sub(" ", "") # => returns "ab c d e f", but leaves a unchanged. > also, the return value will be garbage collected, since nothing is > pointing to it > > b = a.sub(" ", "") # => b is now "ab c d e f", leaves a unchanged > > a = a.sub(" ", "") # => a is now "ab c d e f", the old string is > garbage collected > > a = "a b c d e f" > b = a > a = a.sub(" ", "") # => a is now "ab c d e f", b is still "a b c d e f" > Wrong. Unless you use b = a.dup b will be the same as a as it is pointing to the same object. The result of the sub operation will change b as well as a. > a = "a b c d e f" > a.sub!("", '') #=> a is now "ab c d e f" > > a = "a b c d e f" > b = a.sub!("", '') #=> a is now "ab c d e f", a and b point to the same > object > > a = "abcdef" > b = a.sub!("", '') #=> a is still "abcdef", b is nil > > Note the last bit carefully - sub! modifies the object, and *returns* > either another pointer to the same object if it was modified, or nil > if it wasn't. Therefore the return value of sub! should ideally only > be used to check if the string was modified or not, and then > discarded. > > As for running in a loop, you want either > > 10.times { a.sub!(" ", '')} #=> modifies a string 10 times > > or > > 10.times {a = a.sub(" ", '')} # creates a series of 10 strings, the > intermediate ones being GCd > > try this: > > a = "a b c d e f" > intermediate = [a] > 10.times {|i| intermediate[i+1] = intermediate[i].sub(" ", '')} > p intermediate > I guess my problem is that the sub operations return a nil if they don't make a change rather than the unchanged object. This seems to be inconsistent as you get the changed object back if it works but nothing if it doesn't. Maybe I need to write a version of sub or a method for it that returns the string regardless of whether it was changed or not. > # => ["a b c d e f", "ab c d e f", "abc d e f", "abcd e f", "abcde f", > "abcdef", "abcdef", "abcdef", "abcdef", "abcdef", "abcdef"] > > > martin >