简体   繁体   中英

Ruby - replace words in a string if instances do not match

First time on Stackvoverflow so hope I am posting this correctly & as clear as possible. Please feel free to rip this apart and let me know how to post clearer questions in the future if need be.

Newbie to Ruby here and practising where I can.

I want to know how to replace instances in a string in ruby.

for example:

say I have:

string = 'richard julie richard julie sam letty sam letty'

How would I replace any instance in the string, that does not equal 'richard' or 'julie' & replace with the word richard again?

so the new string would read after said ruby method was implemented:

string = 'richard julie richard julie richard richard richard richard

I have tried using gsub like so:

def string_replace(str)
  if str.include?("sam" || "letty")
    str.gsub! "sam" && "letty", "richard"
  end
end

I already realise there are a lot of problems with this attempt;

  1. When using the boolean operators only one argument is getting evaluated! Could anyone shed any light on why? This also means only one word is being replaces when I need both 'sam' & 'letty' to be replaced for 'richard'.

  2. This attempt is also very limited as it would only replace those instances of those strings sam & letty appearing. Is there a better way that would cover any word that does not equal richard or julie to be replaced for the word richard again?

Any help that could be given on this would be greatly appreciated.

Thank you & happy new year.

Ps how do I use the back tick escapes so I can print blocks of grey to neaten it up? Thanks

Another gsub , using a hash which contains the value "julie" for key "julie", and "richard" for everything else:

string = 'richard julie richard julie sam letty sam letty'
h = Hash.new{"richard"}
h["julie"] = "julie"

p string.gsub(/\w+/, h) # =>"richard julie richard julie richard richard richard richard"

This is a gsub that I think will do what you want:

string = 'richard julie richard julie sam letty sam letty'

string.gsub /\b(?!(richard|julie))\w+/, 'richard'

\\b is a word break and ?!(richard|julie) is a look ahead for not richard nor julie . So this is basically a match for a word break and the letters that follow it, where those letters don't match richard nor julie

For Point 1, include? doesn't take a boolean expression just a truthy value. If you pass a boolean expression, it will return the turthy value.

"sam" && "lenny" # => "lenny"
"sam" || "letty" # => "sam"

For Point 2, this would replace any word that wasn't richard or julie .

def string_replace(string)
  non_removed_words = ['richard', 'julie']
  words = string.split(' ')
  words.map { |w| non_removed_words.include?(w) ? w : 'richard' }.join(' ')
end

Part of your confusion here is that you've slightly misunderstood what the || and && operators do.

|| isn't a general way that an arbitrary method, such as include? , can be used with 2 possible values. It's an operator that says an overall expression is considered true if either side of the || is true. So to say does the string include sam or letty you'd need to write out both conditions in full like this:

if str.include?("sam") || str.include?("letty")

Likewise && is an operator that checks if both of 2 expressions are true, it's not a thing that can be used with gsub! to replace 2 different words in the way you tried.

355E3b 's approach using map is a good way to replace words matching a particular condition, following a general approach of splitting up into a list of words, processing each word and then joining back together again.


One other thing you might find confusing at first, but will later discover is quite handy is that other values are counted is true and false, not just the literal true and false . This is what people mean when they talk about truthy and falsey . Any string is truthy, so:

"sam" || "letty" # => "sam"

"sam" is truthy so no need for Ruby to look at the second value to know the overall thing is truthy, so it has the value of the left hand side.

"sam" && "lenny" # => "lenny"

for an and condition Ruby will need to check the left side first, and if that's truthy then check the right hand side to determine if the overall thing is truthy. so in this case the overall expression has the value of from the right.

Pure regexp solution:

input = 'richard julie richard julie sam letty sam letty'
left = %w|richard julie|
subst = 'richard'

input.gsub(/\w+/) { |m| left.include?(m) ? m : subst }
#⇒ "richard julie richard julie richard richard richard richard"

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM