ruby中字符串中所选字符替换的所有可能组合

我想知道是否有一种简单的方法可以用简单的方式在ruby中完成所选字符替换的每个组合。

一个例子:

string = "this is a test" subs = ['a'=>'@','i'=>'!','s'=>'$'] subs.combination.each { |c| string.gsub c } 

会屈服

  "this is @ test" "th!s !sa test" "thi$ i$ a te$t" "th!s !s @ test" "thi$ i$ @ te$t" "th!$ !$ a te$t" "th!$ !$ @ te$t" 

谢谢您的帮助!

 string = "this is a test" subs = ['a'=>'@','i'=>'!','s'=>'$'] subs = subs.first.map(&:to_a) 1.upto(subs.length).each do |n| subs.combination(n).each do |a| p a.each_with_object(string.dup){|pair, s| s.gsub!(*pair)} end end 

我会这样做:

 string = "this is a test" subs = {'a'=>'@','i'=>'!','s'=>'$'} keys = subs.keys combinations = 1.upto(subs.size).flat_map { |i| keys.combination(i).to_a } combinations.each do |ary| new_string = string.dup ary.each { |c| new_string.gsub!(c,subs) } puts new_string end 

产量

 this is @ test th!s !sa test thi$ i$ a te$t th!s !s @ test thi$ i$ @ te$t th!$ !$ a te$t th!$ !$ @ te$t 

我使用String#gsub(pattern, hash)

 string = "this is a test" subs = {'a'=>'@','i'=>'!','s'=>'$'} # copied from @ArupRakshit keys = subs.keys 

核心代码:

 1.upto(keys.length).flat_map { |i| keys.combination(i).flat_map { |c| string.gsub(/[#{c.join}]/, subs) } } 

输出:

 => ["this is @ test", "th!s !sa test", "thi$ i$ a te$t", "th!s !s @ test", "thi$ i$ @ te$t", "th!$ !$ a te$t", "th!$ !$ @ te$t"] 

其他方式:

 string = "this is a test" subs = [{"a"=>"@"}, {"i"=>"!"}, {"s"=>"$"}] subs.repeated_combination(subs.size) .map {|e| string.gsub(/./) {|c| (g = e.find {|h| h.key?(c)}) ? g[c] : c}} .uniq #=> ["this is @ test", "th!s !s @ test", "thi$ i$ @ te$t", "th!$ !$ @ te$t", # "th!s !sa test", "th!$ !$ a te$t", thi$ i$ a te$t"] 

说明:

 a = subs.repeated_combination(subs.size) # Enumerator... a.to_a # [[{"a"=>"@"},{"a"=>"@"},{"a"=>"@"}], [{"a"=>"@"},{"a"=>"@"},{"i"=>"!"}], # [{"a"=>"@"},{"a"=>"@"},{"s"=>"$"}], [{"a"=>"@"},{"i"=>"!"},{"i"=>"!"}], # [{"a"=>"@"},{"i"=>"!"},{"s"=>"$"}], [{"a"=>"@"},{"s"=>"$"},{"s"=>"$"}], # [{"i"=>"!"},{"i"=>"!"},{"i"=>"!"}], [{"i"=>"!"},{"i"=>"!"},{"s"=>"$"}], # [{"i"=>"!"},{"s"=>"$"},{"s"=>"$"}], [{"s"=>"$"},{"s"=>"$"},{"s"=>"$"}]] b = a.map {|e| string.gsub(/./) {|c| (g = e.find {|h| h.key?(c)}) ? g[c] : c}} #=> ["this is @ test", "th!s !s @ test", "thi$ i$ @ te$t", "th!s !s @ test", # "th!$ !$ @ te$t", "thi$ i$ @ te$t", "th!s !sa test", "th!$ !$ a te$t", # "th!$ !$ a te$t", "thi$ i$ a te$t"] 

要查看如何计算b ,请考虑传递给块的第二个元素:

  e = [{"a"=>"@"},{"a"=>"@"},{"i"=>"!"}] 

由于正则表达式,/。/, gsubstring每个字符c传递给块

  {|c| (g = e.find {|h| h.key?(c)}) ? g[c] : c} 

搜索e以确定三个哈​​希中的任何一个是否具有c作为关键字。 如果找到一个,即g ,则用g[c]替换字符c ; 否则,角色保持不变。

请注意, e的前两个元素是相同的。 通过将第一行更改为:可以提高效率:

  subs.repeated_combination(subs.size).map(&:uniq) 

但效率不是这种方法的优点之一。

回到主要计算,最后一步是:

 b.uniq #=> ["this is @ test", "th!s !s @ test", "thi$ i$ @ te$t", "th!$ !$ @ te$t", # "th!s !sa test", "th!$ !$ a te$t", "thi$ i$ a te$t"] 

一线function解决方案

 string = "this is a test" subs = {'a'=>'@','i'=>'!','s'=>'$'} (1..subs.size).flat_map { |n| subs.keys.combination(n).to_a }.map { |c| string.gsub(/[#{c.join}]/, subs) } # => ["this is @ test", "th!s !sa test", "thi$ i$ a te$t", "th!s !s @ test", "thi$ i$ @ te$t", "th!$ !$ a te$t", "th!$ !$ @ te$t"]