Tommy K
Tommy K

Reputation: 1807

Generating a character class

I'm trying to censor letters in a word with word.gsub(/[^#{guesses}]/i, '-'), where word and guesses are strings.

When guesses is "", I get this error RegexpError: empty char-class: /[^]/i. I could sort such cases with an if/else statement, but can I add something to the regex to make it work in one line?

Upvotes: 1

Views: 67

Answers (3)

tadman
tadman

Reputation: 211580

You have two options. One is to avoid testing if your matches are empty, that is:

unless (guesses.empty?)
  word.gsub(/^#{Regex.escape(guesses)}/i, '-')
end

Although that's not your intention, it's really the safest plan here and is the most clear in terms of code.

Or you could use the tr function instead, though only for non-empty strings, so this could be substituted inside the unless block:

word.tr('^' + guesses.downcase + guesses.upcase, '-')

Generally tr performs better than gsub if used frequently. It also doesn't require any special escaping.

Edit: Added a note about tr not working on empty strings.

Since tr treats ^ as a special case on empty strings, you can use an embedded ternary, but that ends up confusing what's going on considerably:

word.tr(guesses.empty? ? '' : ('^' + guesses.downcase + guesses.upcase), '-')

Upvotes: 1

sawa
sawa

Reputation: 168101

This may look somewhat similar to tadman's answer.

Probably you should keep the string that represents what you want to hide, instead of what you want to show. Let's say this is remains. Then, it would be easy as:

word.tr(remains.upcase + remains.downcase, "-")

Upvotes: 0

Wiktor Stribiżew
Wiktor Stribiżew

Reputation: 626802

Since you are only matching (or not matching) letters, you can add a non-letter character to your regex, e.g. # or %:

word.gsub(/[^%#{guesses}]/i, '-')

See IDEONE demo

If #{guesses} is empty, the regex will still be valid, and since % does not appear in a word, there is no risk of censuring some guessed percentage sign.

Upvotes: 1

Related Questions