Is there a replacement for sub?

You are absolutely correct!!! Your improvement does what you expect it to do.

···

ruby-talk-admin@ruby-lang.org wrote:

bbiker wrote:
<snip>

You might consider adding the following, so you have a matching
replacement set for sub, sub!, gsub, and gsub!

You can think of gsubn and gsubn! as no nil returns :>)

class String
  def subn!(pattern, replacement, n = 1)
    n.times { self.sub!(pattern, replacement) }
    self
  end

  def subn(pattern, replacement, n = 1)
    return self if n < 1
    @str = self.sub(pattern, replacement)
    (n-1).times { @str = @str.sub(pattern, replacement) }

Is there any reason you used the above three lines instead of:
      @str = self
      n.times { @str = @str.sub(pattern, replacement) }

As I mentioned in an earlier post times seems to work fine with zero or negative values not changing the string. The replacement code seems "cleaner" but I may be missing some gotcha that your code prevents.
Again, thanks for improving my knowledge of Ruby.