AnApprentice
AnApprentice

Reputation: 110960

How to replace a string and conserve capitalisation?

With Ruby, is it possible to replace a string and conserve capitalisation.

Idea is to match "good day" and turn it into "holler" and preserve the original capitalisation. Example:

Before:

Good day to you sir and lady.
Hello and good day.

After:

Holler to you sir and lady.
Hello and holler.

Upvotes: 2

Views: 242

Answers (6)

Ruby Racer
Ruby Racer

Reputation: 5740

If you are planning to keep part of the string and append to it, use back reference and case-insensitive search pattern

yourstring.gsub(/(good day)/i, "\\1 and good night")

You can find explanation on how regular expressions work in ruby in rubular

Update

Since, as you state in your comment and your updated question, you want the first letter of the replacement capitalized or not, according to pattern, I think this slightly verbose yet efficient gsub approach can help you:

string = "Good day to you sir and lady. \nHello and good day."
puts string.gsub(/[gG]ood day/, 'good day' =>'holler', 'Good day'=>'Holler')
# Holler to you sir and lady.
# Hello and holler.

As per ruby 1.8.7, gsub can accept a hash as a second parameter with alternative replacements of the possible matches the pattern describes. Thus, the above syntax is equivalent to:

puts string.gsub(/[gG]ood day/, {'good day' =>'holler', 'Good day'=>'Holler'})

Upvotes: 1

Eric Duminil
Eric Duminil

Reputation: 54233

This method :

  • Applies a case-insensitive search for old_str in text
  • For every old_str found :
    • it iterates new_str and old_str characters in parallel
    • it applies the old_str case on new_str

def case_aware_replace(text, old_str, new_str)
  text.gsub(/#{old_str}/i) do |word|
    new_str.chars.zip(word.chars).map do |new_char, old_char|
      if old_char
        old_char.downcase == old_char ? new_char : new_char.upcase
      else
        new_char
      end
    end.join
  end
end

puts case_aware_replace('Good day to you sir and lady.', 'good day', 'holler')
#=> Holler to you sir and lady.

puts case_aware_replace('Hello and good day.', 'good day', 'holler')
#=> Hello and holler.

puts case_aware_replace('HELLO GRANDMA!', 'hello', 'hi')
#=> HI GRANDMA!

puts case_aware_replace('AaAaAaA', 'a', 'b')
#=> BbBbBbB

puts case_aware_replace('AaAaAaA', 'a', 'b ')
#=> B b B b B b B

puts case_aware_replace(case_aware_replace(case_aware_replace('IBM', 'i', 'international '),'b', 'business '),'m', 'machines ')
#=> International Business Machines

Upvotes: 1

Zzz
Zzz

Reputation: 1703

a = 'Good day to you sir and lady.
Hello and good day.'

a.gsub!('Good day', 'Hellor').gsub!('good day', 'hellor')

would return

Hellor to you sir and lady.                                                                                                                                                                             
Hello and hellor.   

There are only two cases (assuming only initials can be capitalised), replacing two cases directly should be sufficient.

Upvotes: -1

John Hayes-Reed
John Hayes-Reed

Reputation: 1428

you can use the Regexp escape method with the ignore case option to do such a thing:

reg = Regexp.new(Regexp.escape("good day"), Regexp::IGNORECASE)

"good day".gsub(reg){|match| "#{match} and good night" }
=> "good day and good night"


"Good dAy".gsub(reg){|match| "#{match} and good night" }
=> "Good dAy and good night"

EDIT to match the updated question

using a similar idea to the answer for the original question

"Good day".gsub(reg){|match| "#{match.capitalize == match ? 'Holler' : 'holler'} and good night" }
=> "Holler and good night"

"good day".gsub(reg){|match| "#{match.capitalize == match ? 'Holler' : 'holler'} and good night" }
=> "holler and good night"

Upvotes: 1

Deepak Mahakale
Deepak Mahakale

Reputation: 23671

You can pass a block to gsub and you can manipulate the matched string

And the option i passed will make the regex case insensitive

string = "Good day to you sir and lady."

string.gsub(/good day/i) { |m| "#{m} and good night" }

#=> "Good day and good night to you sir and lady."

string = "Hello and good day."

string.gsub(/good day/i) { |m| "#{m} and good night" }

#=> "Hello and good day and good night."

Refer gsub

Upvotes: 1

marmeladze
marmeladze

Reputation: 6564

sure there will be more elegant solutions, but this can also help.

2.3.1 :003 > a = "Good day to you sir and lady".downcase.gsub('good day', 'good day and good night').capitalize
 => "Good day and good night to you sir and lady" 

what i've done is,

  • changed all letters to downcase,
  • substituted the relevant parts,
  • then capitalized.

Upvotes: -1

Related Questions