String#ggsub

I occasionally find myself with gsub regexp that either eat too much, or work within a nesting, such that I need to run gsub more than once in order to get the desired end result. The code I end up writing tends to be of the form:

while foo.gsub!( /.../, ... ); end

Frankly, I really don't like that. It's like JS people who write things like:
for ( var walkerNode = this; walkerNode.parent; walkerNode = walkerNode.parent ){}
'abusing' the for loop construct to hold their logic.

Is there some other form in Ruby of "keep doing this until it returns nil" that is less...gross?

Gavin Kistner wrote:

I occasionally find myself with gsub regexp that either eat too much, or work within a nesting, such that I need to run gsub more than once in order to get the desired end result. The code I end up writing tends to be of the form:

while foo.gsub!( /.../, ... ); end

Frankly, I really don't like that. It's like JS people who write things like:
for ( var walkerNode = this; walkerNode.parent; walkerNode = walkerNode.parent ){}
'abusing' the for loop construct to hold their logic.

Is there some other form in Ruby of "keep doing this until it returns nil" that is less...gross?

loop{break if foo.gsub!( /.../, ... ).nil?}

?

its more explicit and avoids the empty body, but ....
i don't like it either :slight_smile:

cheers

Simon

I'm kinda curious, can we see an example of a regex where this was necessary?

···

On Sep 25, 2005, at 4:25 PM, Gavin Kistner wrote:

I occasionally find myself with gsub regexp that either eat too much, or work within a nesting, such that I need to run gsub more than once in order to get the desired end result. The code I end up writing tends to be of the form:

while foo.gsub!( /.../, ... ); end

Of course, it's trivial to roll one up:

#!/usr/local/bin/ruby -w

module Kernel
     def complete
         loop { break unless yield }
     end
end

if __FILE__ == $0
     digits = "3211"
     complete { digits.gsub!(/(\d)\1+/) { |d| d[0, 1].to_i + 1 } }
     p digits # => "4"
end

__END__

Though I do realize that's not what you asked.

James Edward Gray II

···

On Sep 25, 2005, at 3:25 PM, Gavin Kistner wrote:

I occasionally find myself with gsub regexp that either eat too much, or work within a nesting, such that I need to run gsub more than once in order to get the desired end result. The code I end up writing tends to be of the form:

while foo.gsub!( /.../, ... ); end

Frankly, I really don't like that. It's like JS people who write things like:
for ( var walkerNode = this; walkerNode.parent; walkerNode = walkerNode.parent ){}
'abusing' the for loop construct to hold their logic.

Is there some other form in Ruby of "keep doing this until it returns nil" that is less...gross?

g = foo.gsub!( /.../, ... ) until g.nil?

Oh better:

  foo.gsub!( /.../, ... ) while $~

T.

Gavin Kistner wrote:

I occasionally find myself with gsub regexp that either eat too much,
or work within a nesting, such that I need to run gsub more than once
in order to get the desired end result. The code I end up writing
tends to be of the form:

while foo.gsub!( /.../, ... ); end

Frankly, I really don't like that. It's like JS people who write
things like:
for ( var walkerNode = this; walkerNode.parent; walkerNode =
walkerNode.parent ){}
'abusing' the for loop construct to hold their logic.

Is there some other form in Ruby of "keep doing this until it returns
nil" that is less...gross?

Another one

1 while foo.gsub!( /.../, ... )

Kind regards

    robert

Here's a pared-down example from this week's ruby quiz:

class Array; def random; self[ rand( self.length ) ]; end; end

class String
   def variation
     out = self.dup
     while out.gsub!( /\(([^())?]+)\)(\?)?/ ){
       ( $2 && ( rand > 0.5 ) ) ? '' : $1.split( '|' ).random
     }; end
     out
   end
end

q = "(How (much|many)|What) is (the (value|result) of)? 10 + 2?"
10.times{ puts q.variation }
#=> What is the value of 10 + 2?
#=> How many is 10 + 2?
#=> What is 10 + 2?
#=> How many is 10 + 2?
#=> What is the value of 10 + 2?
#=> What is 10 + 2?
#=> What is the result of 10 + 2?

···

On Sep 25, 2005, at 3:33 PM, Logan Capaldo wrote:

I occasionally find myself with gsub regexp that either eat too much, or work within a nesting, such that I need to run gsub more than once in order to get the desired end result. The code I end up writing tends to be of the form:

while foo.gsub!( /.../, ... ); end

I'm kinda curious, can we see an example of a regex where this was necessary?

That's not bad, thanks!

···

On Sep 25, 2005, at 4:21 PM, Trans wrote:

g = foo.gsub!( /.../, ... ) until g.nil?

In Message-Id: <1127687058.509239.99690@f14g2000cwb.googlegroups.com>
"Trans" <transfire@gmail.com> writes:

Oh better:

  foo.gsub!( /.../, ... ) while $~

    irb(main):001:0> s = 'foo'
    => "foo"
    irb(main):002:0> s =~ /never match/
    => nil
    irb(main):003:0> s.gsub!(/\w/, '*') while $~
    => nil
    irb(main):004:0> s
    => "foo"

So that's not context free.

I tend to use

    true while s.gsub!(/.../, ...)

but probably OP doesn't like that because of extra `true'.

···

--
kjana@dm4lab.to September 26, 2005
What is done can't be undone.

How about a helper method

  def rep(&blk)
    r = yield(&blk) until r.nil?
  end

  rep { foo.gsub!( /.../, ... ) }

T.

James Edward Gray II wrote:

#!/usr/local/bin/ruby -w

module Kernel
     def complete
         loop { break unless yield }
     end
end

if __FILE__ == $0
     digits = "3211"
     complete { digits.gsub!(/(\d)\1+/) { |d| d[0, 1].to_i + 1 } }
     p digits # => "4"
end

     complete { digits.gsub!(/(\d)\1+/) { $1.to_i + 1 } }

Hi --

···

On Mon, 26 Sep 2005, YANAGAWA Kazuhisa wrote:

In Message-Id: <1127687058.509239.99690@f14g2000cwb.googlegroups.com>
"Trans" <transfire@gmail.com> writes:

Oh better:

  foo.gsub!( /.../, ... ) while $~

   irb(main):001:0> s = 'foo'
   => "foo"
   irb(main):002:0> s =~ /never match/
   => nil
   irb(main):003:0> s.gsub!(/\w/, '*') while $~
   => nil
   irb(main):004:0> s
   => "foo"

So that's not context free.

I tend to use

   true while s.gsub!(/.../, ...)

but probably OP doesn't like that because of extra `true'.

If you had reason to save the last match, you could do:

   m = $~ while s.gsub!(/.../, ...)

:slight_smile: Also this would work, but it's probably too verbose:

   begin s.gsub!(/\w/,"*") end while $~

David

--
David A. Black
dblack@wobblini.net

So that's not context free.

Ah, good point. Well,

  ''=~//; foo.gsub!( /.../, ... ) while $~

But that's more fitting an obsucure code contest :slight_smile:

T.

Sorry, just woke up:

  def rep
    r = yield until r.nil?
  end

T.

Hi --

Sorry, just woke up:

def rep
   r = yield until r.nil?
end

Or (modeled on some earlier suggestions):

   def rep
     true until yield.nil?
   end

or if false is OK:

   def rep
     true while yield
   end

I love watching Ruby code progressively disappear from the screen (and
still be clear) :slight_smile:

David

···

On Mon, 26 Sep 2005, Trans wrote:

--
David A. Black
dblack@wobblini.net

Mostly I don't like it for the confusing/vapid nature of true there. But it makes me think that I sort of like:

:go while s.gsub!( /.../, ... )

or perhaps

while s.gsub!( /.../, ... )
     # Keep on truckin'!
end

or perhaps

while s.gsub!( /.../, ... )
     :ya_cant_and_ya_wont_and_ya_dont_stop
end

:slight_smile:

···

On Sep 25, 2005, at 5:09 PM, YANAGAWA Kazuhisa wrote:

I tend to use

    true while s.gsub!(/.../, ...)

but probably OP doesn't like that because of extra `true'.

David A. Black wrote:

Hi --

Sorry, just woke up:

def rep
   r = yield until r.nil?
end

Or (modeled on some earlier suggestions):

   def rep
     true until yield.nil?
   end

or if false is OK:

   def rep
     true while yield
   end

I love watching Ruby code progressively disappear from the screen (and
still be clear) :slight_smile:

Definitely! Now you arrived at my solution - only you use true instead of
1 (three more characters!). :slight_smile:

Kind regards

    robert

···

On Mon, 26 Sep 2005, Trans wrote:

Hi --

···

On Mon, 26 Sep 2005, Robert Klemme wrote:

David A. Black wrote:

Hi --

On Mon, 26 Sep 2005, Trans wrote:

Sorry, just woke up:

def rep
   r = yield until r.nil?
end

Or (modeled on some earlier suggestions):

   def rep
     true until yield.nil?
   end

or if false is OK:

   def rep
     true while yield
   end

I love watching Ruby code progressively disappear from the screen (and
still be clear) :slight_smile:

Definitely! Now you arrived at my solution - only you use true instead of
1 (three more characters!). :slight_smile:

I was basing it on:
http://www.ruby-talk.org/cgi-bin/scat.rb/ruby/ruby-talk/157559
but was too lazy to look it up -- hence the vague attribution :slight_smile:

David

--
David A. Black
dblack@wobblini.net

David A. Black wrote:

Hi --

David A. Black wrote:

Hi --

Sorry, just woke up:

def rep
   r = yield until r.nil?
end

Or (modeled on some earlier suggestions):

   def rep
     true until yield.nil?
   end

or if false is OK:

   def rep
     true while yield
   end

I love watching Ruby code progressively disappear from the screen
(and still be clear) :slight_smile:

Definitely! Now you arrived at my solution - only you use true
instead of 1 (three more characters!). :slight_smile:

I was basing it on:
http://www.ruby-talk.org/cgi-bin/scat.rb/ruby/ruby-talk/157559
but was too lazy to look it up -- hence the vague attribution :slight_smile:

Ooops! I overlooked that one. /me smacks himself So the attribution
should of course go to Yanagawa Kazuhisa (I never know which is the
surname and which the christian name with asian names.).

I'll shut up now.

    robert

···

On Mon, 26 Sep 2005, Robert Klemme wrote:

On Mon, 26 Sep 2005, Trans wrote: