From: bbiker Date: 2007-07-22T16:35:06+09:00 Subject: Re: Is there a replacement for sub? On Jul 21, 11:40 pm, "Michael W. Ryder" <_mwry...@worldnet.att.net> wrote: > Bernard Kenik wrote: > > ruby-talk-ad...@ruby-lang.org wrote: > > >> ------------------------------------------------------------------------ > > >> Subject: > >> Re: Is there a replacement for sub? > >> From: > >> "Robert Dober" > >> Date: > >> Fri, 20 Jul 2007 20:49:07 +0900 > >> To: > >> ruby-t...@ruby-lang.org (ruby-talk ML) > > >> To: > >> ruby-t...@ruby-lang.org (ruby-talk ML) > > >> 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) > > > The primary problem is that sub! returns nil when no substitutions are > > made. > > > I have similar problem with Array#flatten!, Array#uniq! since it causes > > problem when chaining! > > My solution has been to override these bang! methods to return self even > > when the bang! method did not have to change the receiver. > > > for sub! I would override the sub! method as follow > > > class String > > alias old_sub! sub! > > def sub!(pattern, replacement) > > self.old_sub!(pattern, replacement) > > self > > end > > end > > And this can easily be expanded to do what I was trying to do in the > first place! Adding the following method with your replacement method: > > class String > def subn!(pattern, replacement, n=1) > n.times do > self.sub!(pattern, replacement) > end > end > end > > With this I can specify a.subn!(' ', '', 10) and it will return 'abcdef' > just like I was looking for. It will work with zero or negative values > returning 'a b c d e f', again like I would expect. Of course if you > enter a non-integer value it will error out in its current state but the > error is from the times method. > > > As a user of a method, I really do not care if the method did not have > > to do anything so long as the object is in the desired state. > > I too hate surprises. > > > > > For an array such as arr = [1,2,3,4,5,6], I can safely chain the bang! > > methods without worrying about nil returns from flatten! and uniq! > > > arr.flatten!.uniq!.sort! # NO ERROR MSG "undefined method `uniq!' for > > nil:NilClass (NoMethodError)" because flatten! would have returned nil > > p arr => [1, 2, 3, 4, 5, 6]- Hide quoted text - > > - Show quoted text -- Hide quoted text - > > - Show quoted text - Note that as written, subn! returns n. So if you need to do some chaining, you should change subn! as follows: def subn!(pattern, replacement, n=1) n.times { self.sub!(pattern, replacement) } self end str = "a b c d e f g h i j" str.subn!(/ /,'',2).reverse! # won't produce an error msg such as C:/Documents ... /rb5C.tmp:30: undefined method `reverse!' for 1:Fixnum (NoMethodError) instead of => "j i h g f e d cba"