39
\$\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\$
3
  • 34
    \$\begingroup\$ have you tried LISP? ;-) \$\endgroup\$
    – Dan
    Nov 30, 2015 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, 2015 at 19:12
  • 11
    \$\begingroup\$ @DanPantry: I assume you meant "WITHP"? \$\endgroup\$ Nov 30, 2015 at 19:29

2 Answers 2

35
\$\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\$
2
  • \$\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, 2015 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\$ Nov 30, 2015 at 22:10
21
\$\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
  • 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\$ Nov 30, 2015 at 18:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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