Is there a replacement for sub?

I was trying to come up with a way to remove x instances of a character from a string and came up with a problem. If I enter:

a = "a b c d e f"
for i in 1..3
   a = a.sub!(' ', '')
end
puts a ==> returns 'abcd e f' which is correct.

But if I enter:

a = "a b c d e f"
for i in 1..10
   a = a.sub!(' ', '')
end
puts a ==> returns error.rb:3: private method `sub!' called for nil:NilClass (NoMethodError, and a is now nil.

What I am looking for is a way to remove the first n instances of a blank from the string without wiping out the string if it does not contain at least n blanks. I assume there is a way to do this with regular expressions, but have not found it yet. This is something an editor I liked, UCEDIT, on the CDC Cyber had in the 70's.

sub! modifies the string in place, so you don't need to say a = a.sub!
(' ',''). a is already changing. And since sub! is modifying in
place, it returns nil if no changes are being made, and you end up
setting a to nil when that happens.

a = 'a b c d e f'
10.times { a.sub!(' ','')}
puts a # 'abcdef'

HTH,
Chris

···

On Jul 19, 8:59 pm, "Michael W. Ryder" <_mwry...@worldnet.att.net> wrote:

I was trying to come up with a way to remove x instances of a character
from a string and came up with a problem. If I enter:

a = "a b c d e f"
for i in 1..3
   a = a.sub!(' ', '')
end
puts a ==> returns 'abcd e f' which is correct.

But if I enter:

a = "a b c d e f"
for i in 1..10
   a = a.sub!(' ', '')
end
puts a ==> returns error.rb:3: private method `sub!' called for
nil:NilClass (NoMethodError, and a is now nil.

What I am looking for is a way to remove the first n instances of a
blank from the string without wiping out the string if it does not
contain at least n blanks. I assume there is a way to do this with
regular expressions, but have not found it yet. This is something an
editor I liked, UCEDIT, on the CDC Cyber had in the 70's.

Michael W. Ryder wrote:

I was trying to come up with a way to remove x instances of a character from a string and came up with a problem. If I enter:

a = "a b c d e f"
for i in 1..3
  a = a.sub!(' ', '')
end
puts a ==> returns 'abcd e f' which is correct.

But if I enter:

a = "a b c d e f"
for i in 1..10
  a = a.sub!(' ', '')
end
puts a ==> returns error.rb:3: private method `sub!' called for nil:NilClass (NoMethodError, and a is now nil.

a.sub! returns nil if no matches are found. You want either:

   a = a.sub(' ', '')

or

   a.sub!(' ', '')

And try using times rather than a for loop and a useless variable:

   3.times { a.sub!(' ', '') }

You could also replace the whole thing with:

   "a b c d e f".split(' ', 4).join

Pete Yandell

How about this?

n = 3
"a b c d e f".sub(/(\S\s){#{n}}/) { |m| m.delete(" ") } # => "abcd e f"
n = 10
"a b c d e f".sub(/(\S\s){#{n}}/) { |m| m.delete(" ") } # => "a b c d e f"

Regards, Morton

···

On Jul 19, 2007, at 11:00 PM, Michael W. Ryder wrote:

I was trying to come up with a way to remove x instances of a character from a string and came up with a problem. If I enter:

a = "a b c d e f"
for i in 1..3
  a = a.sub!(' ', '')
end
puts a ==> returns 'abcd e f' which is correct.

But if I enter:

a = "a b c d e f"
for i in 1..10
  a = a.sub!(' ', '')
end
puts a ==> returns error.rb:3: private method `sub!' called for nil:NilClass (NoMethodError, and a is now nil.

What I am looking for is a way to remove the first n instances of a blank from the string without wiping out the string if it does not contain at least n blanks. I assume there is a way to do this with regular expressions, but have not found it yet. This is something an editor I liked, UCEDIT, on the CDC Cyber had in the 70's.

# a = "a b c d e f"
# for i in 1..3
# a = a.sub!(' ', '')
   ^^^^^
lose that

# end
# puts a ==> returns 'abcd e f' which is correct.

···

From: Michael W. Ryder [mailto:_mwryder@worldnet.att.net]
#
# But if I enter:
#
# a = "a b c d e f"
# for i in 1..10
# a = a.sub!(' ', '')
    ^^^^^
same. lose it.

# end
# puts a ==> returns error.rb:3: private method `sub!' called for
# nil:NilClass (NoMethodError, and a is now nil.

a.sub! will modify a. so, do NOT use a=a.sub!, it's NOT right. just use plain a.sub!. ruby has already simplified it, do not make it simpler :slight_smile:

eg,

C:\family\ruby>cat -n test.rb
     1 puts "---test 3 subs using for---"
     2 a = "a b c d e f"
     3 for i in 1..3
     4 a.sub!(' ', '')
     5 end
     6 puts a
     7
     8 puts "---test 10 subs using for---"
     9 a = "a b c d e f"
    10 for i in 1..10
    11 a.sub!(' ', '')
    12 end
    13 puts a
    14
    15
    16 puts "---test 3 subs using times---"
    17 a = "a b c d e f"
    18 3.times do
    19 a.sub!(' ', '')
    20 end
    21 puts a
    22
    23
    24 puts "---test 10 subs using times---"
    25 a = "a b c d e f"
    26 10.times do
    27 a.sub!(' ', '')
    28 end
    29 puts a

C:\family\ruby>ruby test.rb
---test 3 subs using for---
abcd e f
---test 10 subs using for---
abcdef
---test 3 subs using times---
abcd e f
---test 10 subs using times---
abcdef

C:\family\ruby>

is that clear enough?

kind regards -botp

I was reading this whole thread and I kind of think to be dreaming, I
must have missed something obvious!!!
Anyway maybe this is was OP wants, well I think it is :wink:

529/29 > irb
irb(main):001:0> a='a b c d e f'
=> "a b c d e f"
irb(main):002:0> a.gsub!(" ","")
=> "abcdef"
irb(main):003:0> a
=> "abcdef"
irb(main):004:0>

Consider however using the non inplace version, like e.g.

b = a.gsub(" ","")

HTH
Robert

···

On 7/20/07, Michael W. Ryder <_mwryder@worldnet.att.net> wrote:

I was trying to come up with a way to remove x instances of a character
from a string and came up with a problem. If I enter:

a = "a b c d e f"
for i in 1..3
   a = a.sub!(' ', '')
end
puts a ==> returns 'abcd e f' which is correct.

But if I enter:

a = "a b c d e f"
for i in 1..10
   a = a.sub!(' ', '')
end
puts a ==> returns error.rb:3: private method `sub!' called for
nil:NilClass (NoMethodError, and a is now nil.

What I am looking for is a way to remove the first n instances of a
blank from the string without wiping out the string if it does not
contain at least n blanks. I assume there is a way to do this with
regular expressions, but have not found it yet. This is something an
editor I liked, UCEDIT, on the CDC Cyber had in the 70's.

--
I always knew that one day Smalltalk would replace Java.
I just didn't know it would be called Ruby
-- Kent Beck

a.sub! modifies the string in place, changing only the first occurance.
if it finds something, it returns self, if it finds nothing, it returns
nil (so you can find out whether it changed anything.) So there's no need
to do the a=a.sub!. Just use a.sub! on its own.

a.sum (without the!) always returns a string, whether something was found
or not (in which case it returns the unmodified string), and never
modifies the string itself -- it always returns a copy.

gsub! and gsub work similarly, but they change all matching strings in
one fell swoop. (The g in the name is a holdover from standard UNIX
utilities such as sed, ex, and vi that use the letter g as a modifier to
mean "replace all matches")

--Ken

···

On Fri, 20 Jul 2007 02:59:35 +0000, Michael W. Ryder wrote:

I was trying to come up with a way to remove x instances of a character
from a string and came up with a problem. If I enter:

a = "a b c d e f"
for i in 1..3
   a = a.sub!(' ', '')
end
puts a ==> returns 'abcd e f' which is correct.

But if I enter:

a = "a b c d e f"
for i in 1..10
   a = a.sub!(' ', '')
end
puts a ==> returns error.rb:3: private method `sub!' called for
nil:NilClass (NoMethodError, and a is now nil.

What I am looking for is a way to remove the first n instances of a
blank from the string without wiping out the string if it does not
contain at least n blanks. I assume there is a way to do this with
regular expressions, but have not found it yet. This is something an
editor I liked, UCEDIT, on the CDC Cyber had in the 70's.

--
Ken Bloom. PhD candidate. Linguistic Cognition Laboratory.
Department of Computer Science. Illinois Institute of Technology.
http://www.iit.edu/~kbloom1/

Chris Shea wrote:

···

On Jul 19, 8:59 pm, "Michael W. Ryder" <_mwry...@worldnet.att.net> > wrote:

I was trying to come up with a way to remove x instances of a character
from a string and came up with a problem. If I enter:

a = "a b c d e f"
for i in 1..3
   a = a.sub!(' ', '')
end
puts a ==> returns 'abcd e f' which is correct.

But if I enter:

a = "a b c d e f"
for i in 1..10
   a = a.sub!(' ', '')
end
puts a ==> returns error.rb:3: private method `sub!' called for
nil:NilClass (NoMethodError, and a is now nil.

What I am looking for is a way to remove the first n instances of a
blank from the string without wiping out the string if it does not
contain at least n blanks. I assume there is a way to do this with
regular expressions, but have not found it yet. This is something an
editor I liked, UCEDIT, on the CDC Cyber had in the 70's.

sub! modifies the string in place, so you don't need to say a = a.sub!
(' ',''). a is already changing. And since sub! is modifying in
place, it returns nil if no changes are being made, and you end up
setting a to nil when that happens.

a = 'a b c d e f'
10.times { a.sub!(' ','')}
puts a # 'abcdef'

HTH,
Chris

I think this is where I am having problems understanding Ruby. I have to use a.sub(' ', '') in a for loop but use a.sub!(' ', '') when using a times loop. Why the difference?

Morton Goldberg wrote:

···

On Jul 19, 2007, at 11:00 PM, Michael W. Ryder wrote:

I was trying to come up with a way to remove x instances of a character from a string and came up with a problem. If I enter:

a = "a b c d e f"
for i in 1..3
  a = a.sub!(' ', '')
end
puts a ==> returns 'abcd e f' which is correct.

But if I enter:

a = "a b c d e f"
for i in 1..10
  a = a.sub!(' ', '')
end
puts a ==> returns error.rb:3: private method `sub!' called for nil:NilClass (NoMethodError, and a is now nil.

What I am looking for is a way to remove the first n instances of a blank from the string without wiping out the string if it does not contain at least n blanks. I assume there is a way to do this with regular expressions, but have not found it yet. This is something an editor I liked, UCEDIT, on the CDC Cyber had in the 70's.

How about this?

n = 3
"a b c d e f".sub(/(\S\s){#{n}}/) { |m| m.delete(" ") } # => "abcd e f"
n = 10
"a b c d e f".sub(/(\S\s){#{n}}/) { |m| m.delete(" ") } # => "a b c d e f"

Regards, Morton

Is there nothing in regular expressions where you can tell it to do something up to n times?

And, while you're at it, depending on the situation, sub! returning nil
may be quite useful :

a = "a b c d e f"
for i in 1..1_000
  break unless a.sub!(' ', '')
end

(I.e. breaking if there is nothing else to substitute, instead of
looping 995 times for nothing.)

Fred

···

Le 20 juillet à 11:12, Peña, Botp a écrit :

a.sub! will modify a. so, do NOT use a=a.sub!, it's NOT right.
just use plain a.sub!. ruby has already simplified it, do not make
it simpler :slight_smile:

--
Close the shop, let's take a drive Take a break from 9 to 5
It's so great to be alive, oh yeah We could rent some roller skates
We could skate around the lake
If we don't know how, we'll fake it, oh yeah (Prince, Strollin')

Nope, he wants a method that only replaces the first n occurrences of
the pattern. gsub will not do this - you need to run sub in a loop.
(This is where perl's "continue matching where you left off" would
have been a nice optimisation)

martin

···

On 7/20/07, Robert Dober <robert.dober@gmail.com> wrote:

I was reading this whole thread and I kind of think to be dreaming, I
must have missed something obvious!!!
Anyway maybe this is was OP wants, well I think it is :wink:

529/29 > irb
irb(main):001:0> a='a b c d e f'
=> "a b c d e f"
irb(main):002:0> a.gsub!(" ","")

There is none. a.sub! is an alternative to a = a.sub - wherever you use it.

robert

···

2007/7/20, Michael W. Ryder <_mwryder@worldnet.att.net>:

Chris Shea wrote:
> On Jul 19, 8:59 pm, "Michael W. Ryder" <_mwry...@worldnet.att.net> > > wrote:
>> I was trying to come up with a way to remove x instances of a character
>> from a string and came up with a problem. If I enter:
>>
>> a = "a b c d e f"
>> for i in 1..3
>> a = a.sub!(' ', '')
>> end
>> puts a ==> returns 'abcd e f' which is correct.
>>
>> But if I enter:
>>
>> a = "a b c d e f"
>> for i in 1..10
>> a = a.sub!(' ', '')
>> end
>> puts a ==> returns error.rb:3: private method `sub!' called for
>> nil:NilClass (NoMethodError, and a is now nil.
>>
>> What I am looking for is a way to remove the first n instances of a
>> blank from the string without wiping out the string if it does not
>> contain at least n blanks. I assume there is a way to do this with
>> regular expressions, but have not found it yet. This is something an
>> editor I liked, UCEDIT, on the CDC Cyber had in the 70's.
>
> sub! modifies the string in place, so you don't need to say a = a.sub!
> (' ',''). a is already changing. And since sub! is modifying in
> place, it returns nil if no changes are being made, and you end up
> setting a to nil when that happens.
>
> a = 'a b c d e f'
> 10.times { a.sub!(' ','')}
> puts a # 'abcdef'
>
> HTH,
> Chris
>

I think this is where I am having problems understanding Ruby. I have
to use a.sub(' ', '') in a for loop but use a.sub!(' ', '') when using a
times loop. Why the difference?

There is - kind of. You can use {} to give repetition counts. You can do this

irb(main):004:0> a = "a b c d e f"
=> "a b c d e f"
irb(main):005:0> a.sub(/(?: [^ ]*){3}/) {|m| m.gsub(/ /, '') }
=> "abcd e f"
irb(main):006:0>

Kind regards

robert

···

2007/7/20, Michael W. Ryder <_mwryder@worldnet.att.net>:

Morton Goldberg wrote:
> On Jul 19, 2007, at 11:00 PM, Michael W. Ryder wrote:
>
>> I was trying to come up with a way to remove x instances of a
>> character from a string and came up with a problem. If I enter:
>>
>> a = "a b c d e f"
>> for i in 1..3
>> a = a.sub!(' ', '')
>> end
>> puts a ==> returns 'abcd e f' which is correct.
>>
>> But if I enter:
>>
>> a = "a b c d e f"
>> for i in 1..10
>> a = a.sub!(' ', '')
>> end
>> puts a ==> returns error.rb:3: private method `sub!' called for
>> nil:NilClass (NoMethodError, and a is now nil.
>>
>> What I am looking for is a way to remove the first n instances of a
>> blank from the string without wiping out the string if it does not
>> contain at least n blanks. I assume there is a way to do this with
>> regular expressions, but have not found it yet. This is something an
>> editor I liked, UCEDIT, on the CDC Cyber had in the 70's.
>
> How about this?
>
> n = 3
> "a b c d e f".sub(/(\S\s){#{n}}/) { |m| m.delete(" ") } # => "abcd e f"
> n = 10
> "a b c d e f".sub(/(\S\s){#{n}}/) { |m| m.delete(" ") } # => "a b c d e f"
>
> Regards, Morton
>

Is there nothing in regular expressions where you can tell it to do
something up to n times?

>
> I was reading this whole thread and I kind of think to be dreaming, I
> must have missed something obvious!!!
> Anyway maybe this is was OP wants, well I think it is :wink:
>
> 529/29 > irb
> irb(main):001:0> a='a b c d e f'
> => "a b c d e f"
> irb(main):002:0> a.gsub!(" ","")

Nope, he wants a method that only replaces the first n occurrences of
the pattern. gsub will not do this - you need to run sub in a loop.
(This is where perl's "continue matching where you left off" would
have been a nice optimisation)

I knew I missed something but I did not see what, sorry....

···

On 7/20/07, Martin DeMello <martindemello@gmail.com> wrote:

On 7/20/07, Robert Dober <robert.dober@gmail.com> wrote:

martin

--
I always knew that one day Smalltalk would replace Java.
I just didn't know it would be called Ruby
-- Kent Beck

>
> I was reading this whole thread and I kind of think to be dreaming, I
> must have missed something obvious!!!
> Anyway maybe this is was OP wants, well I think it is :wink:
>
> 529/29 > irb
> irb(main):001:0> a='a b c d e f'
> => "a b c d e f"
> irb(main):002:0> a.gsub!(" ","")

Nope, he wants a method that only replaces the first n occurrences of
the pattern. gsub will not do this - you need to run sub in a loop.

There is a different solution that does not need a loop (see one of my
previous posts).

(This is where perl's "continue matching where you left off" would
have been a nice optimisation)

Well, you can always use the block form with an additional counter

irb(main):012:0> count=0
=> 0
irb(main):013:0> a.gsub(/ /) {count+=1; count<3 ? "" : " "}
=> "abc d e f"

But I guess the other solution is more efficient.

Kind regards

robert

···

2007/7/20, Martin DeMello <martindemello@gmail.com>:

On 7/20/07, Robert Dober <robert.dober@gmail.com> wrote:

OK, is this what you're looking for?

result =
7.times do |n|
    result << "a b c d e f".sub(/(\S\s){0,#{n}}/) { |m| m.delete(" ") }
end
result # =>
    ["a b c d e f", "ab c d e f", "abc d e f", "abcd e f", "abcde f", "abcdef", "abcdef"]

Regards, Morton

···

On Jul 20, 2007, at 3:15 AM, Michael W. Ryder wrote:

Morton Goldberg wrote:

How about this?
n = 3
"a b c d e f".sub(/(\S\s){#{n}}/) { |m| m.delete(" ") } # => "abcd e f"
n = 10
"a b c d e f".sub(/(\S\s){#{n}}/) { |m| m.delete(" ") } # => "a b c d e f"
Regards, Morton

Is there nothing in regular expressions where you can tell it to do something up to n times?

Hi --

···

On Fri, 20 Jul 2007, Robert Klemme wrote:

2007/7/20, Michael W. Ryder <_mwryder@worldnet.att.net>:

Chris Shea wrote:
> On Jul 19, 8:59 pm, "Michael W. Ryder" <_mwry...@worldnet.att.net> >> > wrote:
>> I was trying to come up with a way to remove x instances of a character
>> from a string and came up with a problem. If I enter:
>>
>> a = "a b c d e f"
>> for i in 1..3
>> a = a.sub!(' ', '')
>> end
>> puts a ==> returns 'abcd e f' which is correct.
>>
>> But if I enter:
>>
>> a = "a b c d e f"
>> for i in 1..10
>> a = a.sub!(' ', '')
>> end
>> puts a ==> returns error.rb:3: private method `sub!' called for
>> nil:NilClass (NoMethodError, and a is now nil.
>>
>> What I am looking for is a way to remove the first n instances of a
>> blank from the string without wiping out the string if it does not
>> contain at least n blanks. I assume there is a way to do this with
>> regular expressions, but have not found it yet. This is something an
>> editor I liked, UCEDIT, on the CDC Cyber had in the 70's.
>
> sub! modifies the string in place, so you don't need to say a = a.sub!
> (' ',''). a is already changing. And since sub! is modifying in
> place, it returns nil if no changes are being made, and you end up
> setting a to nil when that happens.
>
> a = 'a b c d e f'
> 10.times { a.sub!(' ','')}
> puts a # 'abcdef'
>
> HTH,
> Chris
>

I think this is where I am having problems understanding Ruby. I have
to use a.sub(' ', '') in a for loop but use a.sub!(' ', '') when using a
times loop. Why the difference?

There is none. a.sub! is an alternative to a = a.sub - wherever you use it.

a.sub! will modify the same string, though, whereas a = a.sub
changes the binding of 'a' to a new string. (Which you probably
didn't mention because it doesn't matter in a given case, but could be
misunderstood out of context :slight_smile:

David

--
* Books:
   RAILS ROUTING (new! http://www.awprofessional.com/title/0321509242\)
   RUBY FOR RAILS (http://www.manning.com/black\)
* Ruby/Rails training
     & consulting: Ruby Power and Light, LLC (http://www.rubypal.com)

Robert Klemme wrote:

···

2007/7/20, Michael W. Ryder <_mwryder@worldnet.att.net>:

Morton Goldberg wrote:
> On Jul 19, 2007, at 11:00 PM, Michael W. Ryder wrote:
>
>> I was trying to come up with a way to remove x instances of a
>> character from a string and came up with a problem. If I enter:
>>
>> a = "a b c d e f"
>> for i in 1..3
>> a = a.sub!(' ', '')
>> end
>> puts a ==> returns 'abcd e f' which is correct.
>>
>> But if I enter:
>>
>> a = "a b c d e f"
>> for i in 1..10
>> a = a.sub!(' ', '')
>> end
>> puts a ==> returns error.rb:3: private method `sub!' called for
>> nil:NilClass (NoMethodError, and a is now nil.
>>
>> What I am looking for is a way to remove the first n instances of a
>> blank from the string without wiping out the string if it does not
>> contain at least n blanks. I assume there is a way to do this with
>> regular expressions, but have not found it yet. This is something an
>> editor I liked, UCEDIT, on the CDC Cyber had in the 70's.
>
> How about this?
>
> n = 3
> "a b c d e f".sub(/(\S\s){#{n}}/) { |m| m.delete(" ") } # => "abcd e f"
> n = 10
> "a b c d e f".sub(/(\S\s){#{n}}/) { |m| m.delete(" ") } # => "a b c d e f"
>
> Regards, Morton
>

Is there nothing in regular expressions where you can tell it to do
something up to n times?

There is - kind of. You can use {} to give repetition counts. You can do this

irb(main):004:0> a = "a b c d e f"
=> "a b c d e f"
irb(main):005:0> a.sub(/(?: [^ ]*){3}/) {|m| m.gsub(/ /, '') }
=> "abcd e f"
irb(main):006:0>

Kind regards

robert

Unfortunately this is much more complicated and much harder to understand, and debug. The editor I mentioned had an argument you passed to the expression that told it to do it one time if it was absent, n number of times, or till the end. Since this was 30 years ago I expected that something like this hadn't been dropped in the interim.

Robert Klemme wrote:

Chris Shea wrote:
>> I was trying to come up with a way to remove x instances of a character
>> from a string and came up with a problem. If I enter:
>>
>> a = "a b c d e f"
>> for i in 1..3
>> a = a.sub!(' ', '')
>> end
>> puts a ==> returns 'abcd e f' which is correct.
>>
>> But if I enter:
>>
>> a = "a b c d e f"
>> for i in 1..10
>> a = a.sub!(' ', '')
>> end
>> puts a ==> returns error.rb:3: private method `sub!' called for
>> nil:NilClass (NoMethodError, and a is now nil.
>>
>> What I am looking for is a way to remove the first n instances of a
>> blank from the string without wiping out the string if it does not
>> contain at least n blanks. I assume there is a way to do this with
>> regular expressions, but have not found it yet. This is something an
>> editor I liked, UCEDIT, on the CDC Cyber had in the 70's.
>
> sub! modifies the string in place, so you don't need to say a = a.sub!
> (' ',''). a is already changing. And since sub! is modifying in
> place, it returns nil if no changes are being made, and you end up
> setting a to nil when that happens.
>
> a = 'a b c d e f'
> 10.times { a.sub!(' ','')}
> puts a # 'abcdef'
>
> HTH,
> Chris
>

I think this is where I am having problems understanding Ruby. I have
to use a.sub(' ', '') in a for loop but use a.sub!(' ', '') when using a
times loop. Why the difference?

There is none. a.sub! is an alternative to a = a.sub - wherever you use it.

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.
b = a.split(' ', 10).join works for this contrived example but I am not sure if it would work for something like replacing the first 12 occurrences of \","\ with \\t\.

···

2007/7/20, Michael W. Ryder <_mwryder@worldnet.att.net>:

> On Jul 19, 8:59 pm, "Michael W. Ryder" <_mwry...@worldnet.att.net> >> > wrote:

robert

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"

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

# => ["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

···

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.