37
\$\begingroup\$

I don't know regex. I want to learn regex, but learning regex just for the sake of regex would be quite boring.

So I decided to learn Ruby as well (which so far looks a lot like Python, which I'm familiar with).

My first program attempts to speak with a combination of both Daffy Duck's lisp and Elmer Fudd's verbal apraxia.

It works quite well, but it looks quite messy already. How does one properly combine Ruby and (repeated) regex substitutions?

def lisp(input)
   return input.downcase.gsub(/s/, "th").gsub(/er/, "uh").gsub(/r|l/, "w").capitalize
end

print lisp("What's your input?")
user_input = gets.chomp

puts lisp(user_input)

I downcase everything to make the regex easier and capitalize at the end to turn it back into a proper sentence.

Usage:

What'th youw input? It's rabbit season!

It'th wabbit theathon!

What'th youw input? My super soaker carries 2 liters of water!

My thupuh thoakuh cawwieth 2 wituhth of watuh!

\$\endgroup\$
  • 34
    \$\begingroup\$ have you tried LISP? ;-) \$\endgroup\$ – Dan Pantry Nov 30 '15 at 13:26
  • 2
    \$\begingroup\$ One thing in Ruby puts does the same as print, and it adds a new line. And this is defiantly hilarious. \$\endgroup\$ – 13aal Nov 30 '15 at 19:12
  • 10
    \$\begingroup\$ @DanPantry: I assume you meant "WITHP"? \$\endgroup\$ – Darrel Hoffman Nov 30 '15 at 19:29
33
\$\begingroup\$

In general, it is bad practice to perform string substitutions in multiple passes, feeding the output back of one substitution into another round of substitutions. (Here is an example of how multiple-pass substitutions can lead to incorrect results.) In this case, it happens to be safe, since none of the outputs overlap with any of the patterns, but I would still recommend a different approach. Fortunately, Ruby makes it easy to do multiple substitutions the right way, with #gsub(patternhash).

return is implicit in Ruby. The last expression evaluated is automatically returned, and everything is an expression.

The standard is to use two spaces of indentation, not three.

def lisp(input)
  input.downcase.gsub(/er|[lrs]/,
    'er' => 'uh',
    'l'  => 'w',
    'r'  => 'w',
    's'  => 'th',
  ).capitalize
end
\$\endgroup\$
  • \$\begingroup\$ The three spaces indentation was unintentional, it was supposed to be four. Very good advice on how to handle the regex, I was wondering how I'd handle overlapping rules. Clear answer, I didn't know this would work as well. \$\endgroup\$ – Mast Nov 30 '15 at 21:46
  • 1
    \$\begingroup\$ That's amazing. I had meant to mention the potential overlap, but I never imagined that the solution would be so simple. You could even construct the regex from the hash if you keep it simple and are not too concerned about performance! \$\endgroup\$ – Jacob Raihle Nov 30 '15 at 22:10
19
\$\begingroup\$

My solution for this is not unique to Ruby - if you have a list of substitutions you want to make, model them as a list (or array), and then loop over the list in your preferred fashion:

def lisp(input)
  substitutions = [
    [/s/, "th"],
    [/er/, "uh"],
    [/r|l/, "w"]
  ]
  substitution_helper(input.downcase, substitutions).capitalize
end

def substitution_helper(input, substitutions)
  substitutions.inject(input) do |text, sub|
    text.gsub(sub[0], sub[1])
  end
end

puts lisp "it's Rabbit season"

It'th wabbit theathon

\$\endgroup\$
  • 1
    \$\begingroup\$ It's worth noting that some languages, such as PHP, allow you to pass an array directly to the function and will do the iterating for you. Doing it this way will also avoid replacing things you've already replaced, just in case your regex matches overlap somehow (eg [[/a/,'e'],[/e/,'i']]) \$\endgroup\$ – Niet the Dark Absol Nov 30 '15 at 18:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.