如果字符串包含数组中包含的一个或多个值,则替换字符串

Replace string if it contains one or more values included in an array

我有一个 Ruby 字符串,例如:"blue green yellow dog cat mouse alpha beta".

我要替换:

换句话说,在我上面的例子中,我希望新字符串是:

"color animal letter"

而不是

"color color color animal animal animal letter letter"

我想出了以下方法:

def convert_string(string)
    if ["cat", "dog", "mouse"].include? key.to_s
      return "animal"
    end
    if ["blue", "yellow", "green"].include? key.to_s
      return "color"
    end
    if ["alpha", "beta"].include? key.to_s
      return "letter"
    end
    return key
end

我怎样才能改进我的方法来达到我的需要?

您可以使用 gsub:

str = "blue green yellow dog cat mouse alpha beta"

str.gsub(/(cat|dog|mouse)/, 'animal')
   .gsub(/(blue|yellow|green)/, 'color')
   .gsub(/(alpha|beta)/, 'letter')
   .split.uniq.join ' '

假设:

str = "gamma blue green yellow dog cat mouse alpha beta"

请注意 str 与问题中给出的示例略有不同。

我假设您想用 "color"(或 "animals" 或 "letters").

这里有两种方法。

#1

这使用 Enumerable#chunk and Object#itself。后者是在 v.2.2 中引入的。对于早期版本,写 ...chunk { |s| s }...

str.split.map do |word|
  case word
  when "blue", "green", "yellow"
    "color"
  when "dog", "cat", "mouse"
    "animal"
  when "alpha", "beta", "gamma"
    "letter"
  end
end.chunk(&:itself).map(&:first).join(' ')
  #=> "letter color animal letter"

map returns:

#=> ["letter", "color", "color", "color", "animal",
#    "animal", "animal", "letter", "letter"] 

然后 chunked。将此数组表示为 arr,分块的替代方法是:

arr.each_with_object([]) { |w,a| a << w if a.empty? || w != a.last }

#2

COLOR  = "color"
ANIMAL = "animal"
LETTER = "letter"

h = { COLOR  => %w{ blue green yellow },      
      ANIMAL => %w{ dog cat mouse },
      LETTER => %w{ alpha beta gamma } }.
      each_with_object({}) { |(k,v), h| v.each { |item| h[item] = k } }
 #=> {"blue"=>"color", "green"=>"color", "yellow"=>"color",
 #    "dog"=>"animal", "cat"=>"animal", "mouse"=>"animal",
 #    "alpha"=>"letter", "beta"=>"letter", "gamma"=>"letter"}

r = /
    \b        # match a word break
    (\w+)     # match a word in capture group 1
    (?:\s)+ # match one or more copies of the matched word, each preceded by a space
    \b        # match a word break
    /x        # extended or free-spacing mode

str.gsub(/\w+/,h).gsub(r,'')
  #=> "letter color animal letter"

str.split.map { |word| h[word] }.chunk(&:itself).map(&:first).join(' ')
  #=> "letter color animal letter"