Is there a replacement for sub?

Discussion in 'Ruby' started by Michael W. Ryder, Jul 20, 2007.

  1. 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, Jul 20, 2007
    #1
    1. Advertising

  2. Michael W. Ryder

    Chris Shea Guest

    On Jul 19, 8:59 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.


    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
     
    Chris Shea, Jul 20, 2007
    #2
    1. Advertising

  3. Michael W. Ryder

    Pete Yandell Guest

    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://notahat.com/
     
    Pete Yandell, Jul 20, 2007
    #3
  4. Michael W. Ryder

    Ken Bloom Guest

    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/~kbloom1/
     
    Ken Bloom, Jul 20, 2007
    #4
  5. 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
     
    Morton Goldberg, Jul 20, 2007
    #5
  6. Chris Shea wrote:
    > On Jul 19, 8:59 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.

    >
    > 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, Jul 20, 2007
    #6
  7. 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?
     
    Michael W. Ryder, Jul 20, 2007
    #7
  8. 2007/7/20, Michael W. Ryder <>:
    > Chris Shea wrote:
    > > On Jul 19, 8:59 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.

    > >
    > > 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, Jul 20, 2007
    #8
  9. 2007/7/20, Michael W. Ryder <>:
    > 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
     
    Robert Klemme, Jul 20, 2007
    #9
  10. Michael W. Ryder

    Guest

    Hi --

    On Fri, 20 Jul 2007, Robert Klemme wrote:

    > 2007/7/20, Michael W. Ryder <>:
    >> Chris Shea wrote:
    >> > On Jul 19, 8:59 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.
    >> >
    >> > 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 :)


    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)
     
    , Jul 20, 2007
    #10
  11. Robert Klemme wrote:
    > 2007/7/20, Michael W. Ryder <>:
    >> 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.
     
    Michael W. Ryder, Jul 20, 2007
    #11
  12. Robert Klemme wrote:
    > 2007/7/20, Michael W. Ryder <>:
    >> Chris Shea wrote:
    >> > On Jul 19, 8:59 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.
    >> >
    >> > 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\.

    > robert
    >
     
    Michael W. Ryder, Jul 20, 2007
    #12
  13. On 7/20/07, Michael W. Ryder <> 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"

    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.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
     
    Martin DeMello, Jul 20, 2007
    #13
  14. Michael W. Ryder

    Peña, Botp Guest

    From: Michael W. Ryder [mailto:]=20
    # a =3D "a b c d e f"
    # for i in 1..3
    # a =3D a.sub!(' ', '')
    ^^^^^
    lose that

    # end
    # puts a =3D=3D> returns 'abcd e f' which is correct.
    #=20
    # But if I enter:
    #=20
    # a =3D "a b c d e f"
    # for i in 1..10
    # a =3D a.sub!(' ', '')
    ^^^^^
    same. lose it.

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

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

    eg,

    C:\family\ruby>cat -n test.rb
    1 puts "---test 3 subs using for---"
    2 a =3D "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 =3D "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 =3D "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 =3D "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
     
    Peña, Botp, Jul 20, 2007
    #14
  15. 2007/7/20, <>:
    > Hi --
    >
    > On Fri, 20 Jul 2007, Robert Klemme wrote:
    >
    > > 2007/7/20, Michael W. Ryder <>:
    > >> Chris Shea wrote:
    > >> > On Jul 19, 8:59 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.
    > >> >
    > >> > 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 :)


    Yes. I was just referring to the assumed different usage in for and
    while loops (see question). Thanks for clarifying!

    Kind regards

    robert
     
    Robert Klemme, Jul 20, 2007
    #15
  16. Michael W. Ryder

    F. Senault Guest

    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 :)


    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
    --
    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')
     
    F. Senault, Jul 20, 2007
    #16
  17. Michael W. Ryder

    Robert Dober Guest

    On 7/20/07, 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.
    >
    >


    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 ;)

    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

    --
    I always knew that one day Smalltalk would replace Java.
    I just didn't know it would be called Ruby
    -- Kent Beck
     
    Robert Dober, Jul 20, 2007
    #17
  18. On 7/20/07, Robert Dober <> 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 ;)
    >
    > 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)

    martin
     
    Martin DeMello, Jul 20, 2007
    #18
  19. Michael W. Ryder

    Robert Dober Guest

    On 7/20/07, Martin DeMello <> wrote:
    > On 7/20/07, Robert Dober <> 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 ;)
    > >
    > > 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....
    >
    > martin
    >
    >



    --
    I always knew that one day Smalltalk would replace Java.
    I just didn't know it would be called Ruby
    -- Kent Beck
     
    Robert Dober, Jul 20, 2007
    #19
  20. 2007/7/20, Martin DeMello <>:
    > On 7/20/07, Robert Dober <> 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 ;)
    > >
    > > 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
     
    Robert Klemme, Jul 20, 2007
    #20
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. THY
    Replies:
    1
    Views:
    399
    Steve C. Orr, MCSD
    Aug 19, 2003
  2. Alexander Schmolck

    re.sub replacement text \-escapes woe

    Alexander Schmolck, Feb 13, 2004, in forum: Python
    Replies:
    4
    Views:
    378
    Alexander Schmolck
    Feb 14, 2004
  3. Vibha Tripathi
    Replies:
    3
    Views:
    2,225
    George Sakkis
    Jul 5, 2005
  4. Ben
    Replies:
    2
    Views:
    911
  5. Lawrence D'Oliveiro

    Death To Sub-Sub-Sub-Directories!

    Lawrence D'Oliveiro, May 5, 2011, in forum: Java
    Replies:
    92
    Views:
    2,062
    Lawrence D'Oliveiro
    May 20, 2011
Loading...

Share This Page