One-liner for regex subsitition (with upcasing)!

Donkey Agony <root@[127.0.0.1]> wrote:

Looking at Steve Litt's Basic Ruby Tutorial at ...

<http://www.troubleshooters.com/codecorn/ruby/basictutorial.htm&gt;

says he's found no easy way to replace the *first* occurrance of a
regex match in a string with it's uppercase equivalent. I got
intrigued and decided to see if I (rank noob) might take a stab at it.

Here's what I came up with, using Steve's framework as a base:

#!/usr/bin/env ruby

string1 = "I will drill for a well in walla walla washington."
string2 = string1.dup

def methodA(s) # this works, but requires 2 lines
   regex = /w.ll/
   s.sub(regex, regex.match(s)[0].upcase)
end

It's especially silly as it matches the RX *twice* against the string.

def methodB(s) # this doesn't work, "will" stays lowercase
   s.sub(/w.ll/, '\0'.upcase)
end

Of course, you just upcase the string '\0'. Your call is equivalent to

s.sub(/w.ll/, '\0')

puts "Original: " + string1 + "\nMethod A: " \
      + methodA(string1)

puts "\n\nOriginal: " + string2 + "\nMethod B: " \
      + methodB(string2)

methodA() returns:

I WILL drill for a well in walla walla washington.

but "will" is still lowercase after methodB(). How might the
one-liner in methodB() be successfully rewritten?

You want the block form of sub:

"I will drill for a well in walla walla washington.".sub(/w.ll/){|m| m.upcase}

=> "I WILL drill for a well in walla walla washington."

"I will drill for a well in walla walla washington.".sub(/w.ll/){|m| m.upcase!}

=> "I WILL drill for a well in walla walla washington."

It's the only reasonable thing to do here because you won't know the matched text before the RX actually matched and that is the point in time where you have to calculate the replacement. The non block form calculates the replacement *before* the invocation - of course you can use \\0, \\1 etc, to access parts - but you can't modify them.

Kind regards

    robert

Donkey Agony <root@[127.0.0.1]> wrote:

Robert Klemme wrote:

def methodB(s) # this doesn't work, "will" stays lowercase
   s.sub(/w.ll/, '\0'.upcase)
end

You want the block form of sub:

"I will drill for a well in walla walla
washington.".sub(/w.ll/){|m| m.upcase}

=> "I WILL drill for a well in walla walla washington."

Ahhhhhhh.

I hope nobody's hurt. :slight_smile:

"I will drill for a well in walla walla
washington.".sub(/w.ll/){|m| m.upcase!}

=> "I WILL drill for a well in walla walla washington."

What's the difference between `upcase` and `upcase!` in these
instances (i.e., inside the block)? In irb, those both seem to yield
the same result. In a program, I had to use `sub!` if modifying the
variable directly, i.e.:

upcase! modifies in place - but it's not a problem here as the match string is a new instance anyway. In this case it boils down to upcase! being more efficint.

string1 = "I will drill for a well in walla walla washington."
string1.sub!(/w.ll/) { |m| m.upcase }
puts string1

(also same result whether using `upcase` or `upcase!` in the block...)

Same story.

It's the only reasonable thing to do here because you won't know the
matched text before the RX actually matched and that is the point in
time where you have to calculate the replacement. The non block form
calculates the replacement *before* the invocation - of course you
can use \\0, \\1 etc, to access parts - but you can't modify them.

Bingo! It's so obvious once you see it. :slight_smile:

Thank you, Robert!

You're welcome!

    robert