在Ruby中显示所有子串替换选项

时间:2014-03-01 02:58:52

标签: ruby

我正在尝试显示子串替换的所有可能选项。例如,如果我有这个字符串:

my_string = “yellow dogs are cooler than brown cats”

以下是可以替换的不同选项:

substitutions = {“yellow” => “black”, “brown” => “grey”}

我如何获得以下输出?

["black dogs are cooler than brown cats", "black dogs are cooler than grey cats", "yellow dogs are cooler than brown cats", "yellow dogs are cooler than grey cats"]

到目前为止,我只是拥有它,正如您所看到的,它没有得到所有选项:

substitutions.each do |key, value|
    puts my_string.sub(key, value) if my_string.include? key
end

5 个答案:

答案 0 :(得分:1)

你真正需要的是打开这个

substitutions = {“yellow” => “black”, “brown” => “grey”}

进入这个:

[{"yellow"=>"yellow", "brown"=>"brown"},
 {"yellow"=>"yellow", "brown"=>"grey"},
 {"yellow"=>"black", "brown"=>"brown"},
 {"yellow"=>"black", "brown"=>"grey"}]

然后你可以简单地循环上面的内容并获得你想要的输出(你最初省略了身份转换,但最简单的是包含它)。以下是将substitutions更改为:

的一种方法
substitutions.to_a[0].product(substitutions.to_a[1]).map do |ary|
  Hash[substitutions.keys.zip ary]
end 

然后它很简单:

_.each do |h|
  p my_string.split.map {|word| h.fetch(word,word) }.join(' ')
end
"yellow dogs are cooler than brown cats"
"yellow dogs are cooler than grey cats"
"black dogs are cooler than brown cats"
"black dogs are cooler than grey cats"

这里我选择了拆分 - > sub each words - >重新加入全球sub操作,因为你可能想要取代“棕色”而不是“布朗尼”。另一方面,这不能非常优雅地处理标点符号,因此您可以选择执行sub或更复杂的正则表达式操作。由你决定。

答案 1 :(得分:1)

这是一个适用于任意数量的替换(不仅仅是两个)的通用解决方案:

my_string = "yellow dogs are cooler than brown cats"
substitutions = {"yellow"=>"black", "brown"=>"grey", "cooler"=>"sweeter"}
keys = substitutions.keys           #=> ["yellow","brown","cooler"]
regx = /\b#{Regexp.union(keys)}\b/  #=> /\b(?:yellow|brown|cooler)\b/
axes = substitutions.to_a           #=> [["yellow", "black"], ["brown", "grey"], ["cooler", "sweeter"]]
maps = axes.shift.product(*axes).map{ |*vals| Hash[ keys.zip(*vals) ] }
maps.each{ |map| p map, my_string.gsub(regx){ |match| map[match] } }

#=> {"yellow"=>"yellow", "brown"=>"brown", "cooler"=>"cooler"}
#=> "yellow dogs are cooler than brown cats"

#=> {"yellow"=>"yellow", "brown"=>"brown", "cooler"=>"sweeter"}
#=> "yellow dogs are sweeter than brown cats"

#=> {"yellow"=>"yellow", "brown"=>"grey", "cooler"=>"cooler"}
#=> "yellow dogs are cooler than grey cats"

#=> {"yellow"=>"yellow", "brown"=>"grey", "cooler"=>"sweeter"}
#=> "yellow dogs are sweeter than grey cats"

#=> {"yellow"=>"black", "brown"=>"brown", "cooler"=>"cooler"}
#=> "black dogs are cooler than brown cats"

#=> {"yellow"=>"black", "brown"=>"brown", "cooler"=>"sweeter"}
#=> "black dogs are sweeter than brown cats"

#=> {"yellow"=>"black", "brown"=>"grey", "cooler"=>"cooler"}
#=> "black dogs are cooler than grey cats"

#=> {"yellow"=>"black", "brown"=>"grey", "cooler"=>"sweeter"}
#=> "black dogs are sweeter than grey cats"

此处的关键是product调用,将[[1,2],[3,4],[5,6]]转换为:

[[1, 3, 5],
 [1, 3, 6],
 [1, 4, 5],
 [1, 4, 6],
 [2, 3, 5],
 [2, 3, 6],
 [2, 4, 5],
 [2, 4, 6]]

换句话说,调用数组和传入的所有数组的所有组合。

使用带有gsub的正则表达式可以提高效率,为每个完整的替换集合执行一次字符串传递。 gsub的块形式产生找到的文本,然后用于查找所需的替换(有时与原始字符串相同)。

答案 2 :(得分:0)

my_string = "yellow dogs are cooler than brown cats"

substitutions = {"yellow" => "black", "brown" => "grey"}

substitutions.each do |k,v|
  if my_string.include?(k)
    my_string.sub! k, v
  end
end

puts my_string

输出:黑狗比灰猫更酷

答案 3 :(得分:0)

另一种方式:

my_array = my_string.split.map(&:strip)

substitutions.to_a
             .repeated_permutation(subs.size)
             .map { |a| Hash[a.uniq] }
             .uniq
             .map { |h| my_array.map { |w| h.key?(w) ? h[w] : w }.join(' ') }
             .concat([my_string])
             .uniq

在失去一些效率的情况下,uniq的前两次出现中的任何一个或两个都可以省略。

步骤:

my_string = "yellow dogs are cooler than brown cats"
substitutions = {"yellow"=>"black", "brown"=>"grey", "cooler"=>"neater"}

a = substitutions.to_a  # 27 elements
  #=> [["yellow", "black"], ["brown", "grey"], ["cooler", "neater"]] 
b = a.repeated_permutation(subs.size)
  #=> => #<Enumerator: [["yellow", "black"],...
  b.to_a
  #=> [[["yellow", "black"], ["yellow", "black"], ["yellow", "black"]],
   #   [["yellow", "black"], ["yellow", "black"], ["brown", "grey"]],
   #   [["yellow", "black"], ["yellow", "black"], ["cooler", "neater"]],
   #   [["yellow", "black"], ["brown", "grey"], ["yellow", "black"]],
   #   ...
   #   [["cooler", "neater"], ["cooler", "neater"], ["cooler", "neater"]]] 

c = b.map {|a| Hash[a.uniq]} # 27 elements
  #=> [{"yellow"=>"black"},
   #   {"brown"=>"grey", "yellow"=>"black"},
   #   {"cooler"=>"neater", "yellow"=>"black"},
   #   {"brown"=>"grey", "yellow"=>"black"},
   #   {"brown"=>"grey", "yellow"=>"black"},
   #   ...
   #   {"brown"=>"grey", "cooler"=>"neater", "yellow"=>"black"},
   #   ...
   #   {"cooler"=>"neater"}]

d = c.uniq
   #=> [{"yellow"=>"black"},
   #    {"brown"=>"grey", "yellow"=>"black"},
   #    {"cooler"=>"neater", "yellow"=>"black"},
   #    {"brown"=>"grey", "cooler"=>"neater", "yellow"=>"black"},
   #    {"brown"=>"grey"},
   #    {"brown"=>"grey", "cooler"=>"neater"},
   #    {"cooler"=>"neater"}] 

e = d.map {|h| my_array.map { |w| h.key?(w) ? h[w] : w }.join(' ') }
     .concat([my_string])
  #=> ["black dogs are cooler than brown cats",
  #    "black dogs are cooler than grey cats",
  #    "black dogs are neater than brown cats",
  #    "black dogs are neater than grey cats",
  #    "yellow dogs are cooler than grey cats",
  #    "yellow dogs are neater than grey cats",
  #    "yellow dogs are neater than brown cats",
  #    "yellow dogs are cooler than brown cats"] 

e.uniq
  # No effect here.  Only relevant for substitutions such as
  # "black=>"yellow" and "grey=>yellow", or "black"=>"black"

答案 4 :(得分:0)

我会这样做:

my_string = "yellow dogs are cooler than brown cats"
substitutions = {"yellow" => "black", "brown" => "grey"}

keys = substitutions.keys
arry_of_comb = 0.upto(substitutions.size).flat_map do |num|
  keys.combination(num).map do |ary| 
    my_string.gsub(/\b#{Regexp.union(ary)}\b/,substitutions) 
  end
end
arry_of_comb
# => ["yellow dogs are cooler than brown cats",
#     "black dogs are cooler than brown cats",
#     "yellow dogs are cooler than grey cats",
#     "black dogs are cooler than grey cats"]