0

I have a string that contains a certain word pattern repeatedly. How can I keep the first occurrence, remove if it is a certain case, and substitute the rest of the pattern if it is a certain case?

rocket = "Meowth, that's right!!! Prepare for trouble meowth, and make it double. MEOWTH ftw!!!"

I want to keep the first instance of "meowth", case insensitive. The rest of "meowth" instance: if it is spelled all caps, it will be replaced with string "team rocket". Other than that, it will be removed.

rocket.gsub(/meowth/i, 'team rocket') 

The code above replaces all "meowth" string instances (case insensitive). How can I keep the first instance and substitute/remove the rest of the instance?

Desired output:

rocket = "Meowth, that's right!!! Prepare for trouble, and make it double. team rocket ftw!!!"
2
  • Is the first instance always at the start of the string? Commented Dec 8, 2016 at 14:07
  • Correct. My apologies, I wasn't clear. First instance means anytime you see "meowth" occur first in the string (case insensitive), even if it spelled MEOWTH, if it is first, it is left as is. Substitution/ removal happens after first occurrence. Commented Dec 8, 2016 at 14:08

2 Answers 2

2

If the first occurrence is at the start of the string, you may use a negative lookahead (?!\A) or lookbehind (?<!\A) at the start of the pattern to exclude the matches at the start of the string:

rocket = "Meowth, that's right!!! Prepare for trouble meowth, and make it double. MEOWTH ftw!!!"
rocket.gsub(/(?!\A)\s*(meowth)/i) { $1.upcase == $1 ? ' team rocket' : '' }
# => Meowth, that's right!!! Prepare for trouble, and make it double. team rocket ftw!!!

See the Ruby demo

If the first instance of the word can be anywhere inside the string, not just at the start of the string, use

rocket.gsub(/(?:\G(?!\A)|\A.*?meowth).*?\K\s*(meowth)/mi) { 
          $1.upcase == $1 ? ' team rocket' : '' 
}

See another Ruby demo.

NOTE: to match meowth as a whole word, enclose it with word boundaries: /(?!\A)\s*\b(meowth)\b/.

Details:

  • (?!\A) - at the current position, there should be no start of string
  • \s* - 0+ whitespaces
  • (meowth) - Group 1 capturing meowth (case-insensitively, due to /i modifier)

Or,

  • (?:\G(?!\A)|\A.*?meowth) - matches a location after a successful match (\G(?!\A)) or a substring from the string start (\A) till the first occurrence of meowth (as .*? match any 0+ chars as few times as possible)
  • .*? - any 0+ chars as few as possible up to the first
  • \K - omit the matched text
  • \s* - 0+ whitespaces
  • (meowth) - meowth (group 1).

Inside the block, the captured value is checked for being ALLCAPS with .upcase, and if it is, the value is replaced with team rocket, esle, removed.

Sign up to request clarification or add additional context in comments.

3 Comments

In case you wonder if it is possible to use a pure regex solution to replace words from the second occurrence if not at the string start, see this Ruby demo.
Hi Wiktor! Thanks for the quick response, but how can I make the non all-caps removed? My apologies if it wasn't clear. Only MEOWTH gets replaced with team rocket; any other occurrence of meowth besides the first one: Meowth, meOwth, meowth, &c. that is not all caps (MEOWTH) need to be removed. See desired output. Thanks! In your case, you have Prepare for trouble team rocket, and..., how can I make it Prepare for trouble, and ....
Doesn't this require the first meowth to be the first word as well?
2

You don't really need a complex regex for this, just pass a block:

str.gsub(/meowth/i).with_index do |w, i|
  if i != 0 && w == 'MEOWTH'
    w = 'team rocket'
  elsif i != 0
    w = ''
  end

  w
end

Comments

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.