[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Is there a replacement for sub?

Michael W. Ryder

7/20/2007 3:00:00 AM

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.
27 Answers

Chris Shea

7/20/2007 4:07:00 AM

0

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

Pete Yandell

7/20/2007 4:57:00 AM

0

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
http://no...

Ken Bloom

7/20/2007 5:01:00 AM

0

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.

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

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

Morton Goldberg

7/20/2007 5:02:00 AM

0

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

Michael W. Ryder

7/20/2007 7:11:00 AM

0

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?

Michael W. Ryder

7/20/2007 7:15:00 AM

0

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?

Robert Klemme

7/20/2007 7:38:00 AM

0

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.

robert

Robert Klemme

7/20/2007 7:42:00 AM

0

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

dblack

7/20/2007 8:14:00 AM

0

Michael W. Ryder

7/20/2007 8:34:00 AM

0

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.